More power management updates for 5.18-rc1
- Add per core DVFS support for QCom SoC (Bjorn Andersson), convert to yaml binding (Manivannan Sadhasivam) and various other fixes to the QCom drivers (Luca Weiss). - Add OPP table for imx7s SoC (Denys Drozdov) and minor fixes (Stefan Agner). - Fix CPPC driver's freq/performance conversions (Pierre Gondois). - Minor generic cleanups (Yury Norov). - Introduce opp-microwatt property to the OPP core, bindings, etc (Lukasz Luba). - Convert DT bindings to schema format and various related fixes (Yassine Oudjana). - Expose OPP's OF node in debugfs (Viresh Kumar). - Add Intel uncore frequency scaling documentation file to its MAINTAINERS entry (Srinivas Pandruvada). - Clean up the AMD P-state driver documentation (Jan Engelhardt). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmJDPHMSHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRxjYYQAJfa7TO+VtoB+0tSKKT0iVI52HVPyvr5 BTlDgCKmpt9/mfwfsa+9+RJ0k78pT8zWMl27VL1fAkF9SXbY13kbFIVyfWDoigiK uAH8hoWHp50PvyZtLHoiIzp5hBl/CLer/66Ys/jo32B5ui2iA50hCJ6W5KIpynT2 yzZBsyGNfak78Y6S6TyeMHR+8ytmfpsuDGMmcs8DVb8Fn6tlcBIfskZcYrimp1Ss IoiDvRvcavY0kZ5tBuzgikSzR4SJ8bx0hPzKnV/n6HCe2CAIg9o5HHnqPT8Su1ar dqI/ghkO+5JvHL1oxlperCDjfXREuYbpx7IkatN8zR9/Xkho5iabW+Pn/E0ZN/e9 boLzAWaHsJxnJkhcwKzOWeYhsbzNuNY+n9LjHHiUH2kgMCUsvPBPIcV5LgUU8oeX 1TXvl36OI883rgymBmi6nBc7+v/lE8qAxFds4M5rsLR173rcSewpiov/uOPgzGhe JyerIpuOU5EWbvJDUCLLgHVLlK+ciu/98wiuWQCWwwiNZBZGEMbxA8Die/0Pq3T5 Nvhh96EDqF6QPACAKTHTSMFDmHC9J78guFvqBSI3XiGDSTlTC+l3twNOT3mU1kUz s9pEwWROBnSg5QsfB/logsjV4q6RcEdSaKSW3bCZ/lRO18/daHFoLH/NlQif626O Jsx3k+vgd2Hv =rsb/ -----END PGP SIGNATURE----- Merge tag 'pm-5.18-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull more power management updates from Rafael Wysocki: "These update ARM cpufreq drivers, the OPP (Operating Performance Points) library and the power management documentation. Specifics: - Add per core DVFS support for QCom SoC (Bjorn Andersson), convert to yaml binding (Manivannan Sadhasivam) and various other fixes to the QCom drivers (Luca Weiss). - Add OPP table for imx7s SoC (Denys Drozdov) and minor fixes (Stefan Agner). - Fix CPPC driver's freq/performance conversions (Pierre Gondois). - Minor generic cleanups (Yury Norov). - Introduce opp-microwatt property to the OPP core, bindings, etc (Lukasz Luba). - Convert DT bindings to schema format and various related fixes (Yassine Oudjana). - Expose OPP's OF node in debugfs (Viresh Kumar). - Add Intel uncore frequency scaling documentation file to its MAINTAINERS entry (Srinivas Pandruvada). - Clean up the AMD P-state driver documentation (Jan Engelhardt)" * tag 'pm-5.18-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (24 commits) Documentation: amd-pstate: grammar and sentence structure updates dt-bindings: cpufreq: cpufreq-qcom-hw: Convert to YAML bindings dt-bindings: dvfs: Use MediaTek CPUFREQ HW as an example Documentation: EM: Describe new registration method using DT OPP: Add support of "opp-microwatt" for EM registration PM: EM: add macro to set .active_power() callback conditionally OPP: Add "opp-microwatt" supporting code dt-bindings: opp: Add "opp-microwatt" entry in the OPP MAINTAINERS: Add additional file to uncore frequency control cpufreq: blocklist Qualcomm sc8280xp and sa8540p in cpufreq-dt-platdev cpufreq: qcom-hw: Add support for per-core-dcvs dt-bindings: power: avs: qcom,cpr: Convert to DT schema arm64: dts: qcom: qcs404: Rename CPU and CPR OPP tables arm64: dts: qcom: msm8996: Rename cluster OPP tables dt-bindings: opp: Convert qcom-nvmem-cpufreq to DT schema dt-bindings: opp: qcom-opp: Convert to DT schema arm64: dts: qcom: msm8996-mtp: Add msm8996 compatible dt-bindings: arm: qcom: Add msm8996 and apq8096 compatibles opp: Expose of-node's name in debugfs cpufreq: CPPC: Fix performance/frequency conversion ...
This commit is contained in:
commit
1d59c3b669
|
@ -19,7 +19,7 @@ Linux kernel. The new mechanism is based on Collaborative Processor
|
|||
Performance Control (CPPC) which provides finer grain frequency management
|
||||
than legacy ACPI hardware P-States. Current AMD CPU/APU platforms are using
|
||||
the ACPI P-states driver to manage CPU frequency and clocks with switching
|
||||
only in 3 P-states. CPPC replaces the ACPI P-states controls, allows a
|
||||
only in 3 P-states. CPPC replaces the ACPI P-states controls and allows a
|
||||
flexible, low-latency interface for the Linux kernel to directly
|
||||
communicate the performance hints to hardware.
|
||||
|
||||
|
@ -27,7 +27,7 @@ communicate the performance hints to hardware.
|
|||
``ondemand``, etc. to manage the performance hints which are provided by
|
||||
CPPC hardware functionality that internally follows the hardware
|
||||
specification (for details refer to AMD64 Architecture Programmer's Manual
|
||||
Volume 2: System Programming [1]_). Currently ``amd-pstate`` supports basic
|
||||
Volume 2: System Programming [1]_). Currently, ``amd-pstate`` supports basic
|
||||
frequency control function according to kernel governors on some of the
|
||||
Zen2 and Zen3 processors, and we will implement more AMD specific functions
|
||||
in future after we verify them on the hardware and SBIOS.
|
||||
|
@ -41,9 +41,9 @@ continuous, abstract, and unit-less performance value in a scale that is
|
|||
not tied to a specific performance state / frequency. This is an ACPI
|
||||
standard [2]_ which software can specify application performance goals and
|
||||
hints as a relative target to the infrastructure limits. AMD processors
|
||||
provides the low latency register model (MSR) instead of AML code
|
||||
provide the low latency register model (MSR) instead of an AML code
|
||||
interpreter for performance adjustments. ``amd-pstate`` will initialize a
|
||||
``struct cpufreq_driver`` instance ``amd_pstate_driver`` with the callbacks
|
||||
``struct cpufreq_driver`` instance, ``amd_pstate_driver``, with the callbacks
|
||||
to manage each performance update behavior. ::
|
||||
|
||||
Highest Perf ------>+-----------------------+ +-----------------------+
|
||||
|
@ -91,26 +91,26 @@ AMD CPPC Performance Capability
|
|||
Highest Performance (RO)
|
||||
.........................
|
||||
|
||||
It is the absolute maximum performance an individual processor may reach,
|
||||
This is the absolute maximum performance an individual processor may reach,
|
||||
assuming ideal conditions. This performance level may not be sustainable
|
||||
for long durations and may only be achievable if other platform components
|
||||
are in a specific state; for example, it may require other processors be in
|
||||
are in a specific state; for example, it may require other processors to be in
|
||||
an idle state. This would be equivalent to the highest frequencies
|
||||
supported by the processor.
|
||||
|
||||
Nominal (Guaranteed) Performance (RO)
|
||||
......................................
|
||||
|
||||
It is the maximum sustained performance level of the processor, assuming
|
||||
ideal operating conditions. In absence of an external constraint (power,
|
||||
thermal, etc.) this is the performance level the processor is expected to
|
||||
This is the maximum sustained performance level of the processor, assuming
|
||||
ideal operating conditions. In the absence of an external constraint (power,
|
||||
thermal, etc.), this is the performance level the processor is expected to
|
||||
be able to maintain continuously. All cores/processors are expected to be
|
||||
able to sustain their nominal performance state simultaneously.
|
||||
|
||||
Lowest non-linear Performance (RO)
|
||||
...................................
|
||||
|
||||
It is the lowest performance level at which nonlinear power savings are
|
||||
This is the lowest performance level at which nonlinear power savings are
|
||||
achieved, for example, due to the combined effects of voltage and frequency
|
||||
scaling. Above this threshold, lower performance levels should be generally
|
||||
more energy efficient than higher performance levels. This register
|
||||
|
@ -119,7 +119,7 @@ effectively conveys the most efficient performance level to ``amd-pstate``.
|
|||
Lowest Performance (RO)
|
||||
........................
|
||||
|
||||
It is the absolute lowest performance level of the processor. Selecting a
|
||||
This is the absolute lowest performance level of the processor. Selecting a
|
||||
performance level lower than the lowest nonlinear performance level may
|
||||
cause an efficiency penalty but should reduce the instantaneous power
|
||||
consumption of the processor.
|
||||
|
@ -149,14 +149,14 @@ a relative number. This can be expressed as percentage of nominal
|
|||
performance (infrastructure max). Below the nominal sustained performance
|
||||
level, desired performance expresses the average performance level of the
|
||||
processor subject to hardware. Above the nominal performance level,
|
||||
processor must provide at least nominal performance requested and go higher
|
||||
the processor must provide at least nominal performance requested and go higher
|
||||
if current operating conditions allow.
|
||||
|
||||
Energy Performance Preference (EPP) (RW)
|
||||
.........................................
|
||||
|
||||
Provides a hint to the hardware if software wants to bias toward performance
|
||||
(0x0) or energy efficiency (0xff).
|
||||
This attribute provides a hint to the hardware if software wants to bias
|
||||
toward performance (0x0) or energy efficiency (0xff).
|
||||
|
||||
|
||||
Key Governors Support
|
||||
|
@ -173,35 +173,34 @@ operating frequencies supported by the hardware. Users can check the
|
|||
``amd-pstate`` mainly supports ``schedutil`` and ``ondemand`` for dynamic
|
||||
frequency control. It is to fine tune the processor configuration on
|
||||
``amd-pstate`` to the ``schedutil`` with CPU CFS scheduler. ``amd-pstate``
|
||||
registers adjust_perf callback to implement the CPPC similar performance
|
||||
update behavior. It is initialized by ``sugov_start`` and then populate the
|
||||
CPU's update_util_data pointer to assign ``sugov_update_single_perf`` as
|
||||
the utilization update callback function in CPU scheduler. CPU scheduler
|
||||
will call ``cpufreq_update_util`` and assign the target performance
|
||||
according to the ``struct sugov_cpu`` that utilization update belongs to.
|
||||
Then ``amd-pstate`` updates the desired performance according to the CPU
|
||||
registers the adjust_perf callback to implement performance update behavior
|
||||
similar to CPPC. It is initialized by ``sugov_start`` and then populates the
|
||||
CPU's update_util_data pointer to assign ``sugov_update_single_perf`` as the
|
||||
utilization update callback function in the CPU scheduler. The CPU scheduler
|
||||
will call ``cpufreq_update_util`` and assigns the target performance according
|
||||
to the ``struct sugov_cpu`` that the utilization update belongs to.
|
||||
Then, ``amd-pstate`` updates the desired performance according to the CPU
|
||||
scheduler assigned.
|
||||
|
||||
|
||||
Processor Support
|
||||
=======================
|
||||
|
||||
The ``amd-pstate`` initialization will fail if the _CPC in ACPI SBIOS is
|
||||
not existed at the detected processor, and it uses ``acpi_cpc_valid`` to
|
||||
check the _CPC existence. All Zen based processors support legacy ACPI
|
||||
hardware P-States function, so while the ``amd-pstate`` fails to be
|
||||
initialized, the kernel will fall back to initialize ``acpi-cpufreq``
|
||||
driver.
|
||||
The ``amd-pstate`` initialization will fail if the ``_CPC`` entry in the ACPI
|
||||
SBIOS does not exist in the detected processor. It uses ``acpi_cpc_valid``
|
||||
to check the existence of ``_CPC``. All Zen based processors support the legacy
|
||||
ACPI hardware P-States function, so when ``amd-pstate`` fails initialization,
|
||||
the kernel will fall back to initialize the ``acpi-cpufreq`` driver.
|
||||
|
||||
There are two types of hardware implementations for ``amd-pstate``: one is
|
||||
`Full MSR Support <perf_cap_>`_ and another is `Shared Memory Support
|
||||
<perf_cap_>`_. It can use :c:macro:`X86_FEATURE_CPPC` feature flag (for
|
||||
details refer to Processor Programming Reference (PPR) for AMD Family
|
||||
19h Model 51h, Revision A1 Processors [3]_) to indicate the different
|
||||
types. ``amd-pstate`` is to register different ``static_call`` instances
|
||||
for different hardware implementations.
|
||||
<perf_cap_>`_. It can use the :c:macro:`X86_FEATURE_CPPC` feature flag to
|
||||
indicate the different types. (For details, refer to the Processor Programming
|
||||
Reference (PPR) for AMD Family 19h Model 51h, Revision A1 Processors [3]_.)
|
||||
``amd-pstate`` is to register different ``static_call`` instances for different
|
||||
hardware implementations.
|
||||
|
||||
Currently, some of Zen2 and Zen3 processors support ``amd-pstate``. In the
|
||||
Currently, some of the Zen2 and Zen3 processors support ``amd-pstate``. In the
|
||||
future, it will be supported on more and more AMD processors.
|
||||
|
||||
Full MSR Support
|
||||
|
@ -210,18 +209,18 @@ Full MSR Support
|
|||
Some new Zen3 processors such as Cezanne provide the MSR registers directly
|
||||
while the :c:macro:`X86_FEATURE_CPPC` CPU feature flag is set.
|
||||
``amd-pstate`` can handle the MSR register to implement the fast switch
|
||||
function in ``CPUFreq`` that can shrink latency of frequency control on the
|
||||
interrupt context. The functions with ``pstate_xxx`` prefix represent the
|
||||
operations of MSR registers.
|
||||
function in ``CPUFreq`` that can reduce the latency of frequency control in
|
||||
interrupt context. The functions with a ``pstate_xxx`` prefix represent the
|
||||
operations on MSR registers.
|
||||
|
||||
Shared Memory Support
|
||||
----------------------
|
||||
|
||||
If :c:macro:`X86_FEATURE_CPPC` CPU feature flag is not set, that means the
|
||||
processor supports shared memory solution. In this case, ``amd-pstate``
|
||||
If the :c:macro:`X86_FEATURE_CPPC` CPU feature flag is not set, the
|
||||
processor supports the shared memory solution. In this case, ``amd-pstate``
|
||||
uses the ``cppc_acpi`` helper methods to implement the callback functions
|
||||
that defined on ``static_call``. The functions with ``cppc_xxx`` prefix
|
||||
represent the operations of acpi cppc helpers for shared memory solution.
|
||||
that are defined on ``static_call``. The functions with the ``cppc_xxx`` prefix
|
||||
represent the operations of ACPI CPPC helpers for the shared memory solution.
|
||||
|
||||
|
||||
AMD P-States and ACPI hardware P-States always can be supported in one
|
||||
|
@ -234,7 +233,7 @@ User Space Interface in ``sysfs``
|
|||
==================================
|
||||
|
||||
``amd-pstate`` exposes several global attributes (files) in ``sysfs`` to
|
||||
control its functionality at the system level. They located in the
|
||||
control its functionality at the system level. They are located in the
|
||||
``/sys/devices/system/cpu/cpufreq/policyX/`` directory and affect all CPUs. ::
|
||||
|
||||
root@hr-test1:/home/ray# ls /sys/devices/system/cpu/cpufreq/policy0/*amd*
|
||||
|
@ -246,38 +245,38 @@ control its functionality at the system level. They located in the
|
|||
``amd_pstate_highest_perf / amd_pstate_max_freq``
|
||||
|
||||
Maximum CPPC performance and CPU frequency that the driver is allowed to
|
||||
set in percent of the maximum supported CPPC performance level (the highest
|
||||
set, in percent of the maximum supported CPPC performance level (the highest
|
||||
performance supported in `AMD CPPC Performance Capability <perf_cap_>`_).
|
||||
In some of ASICs, the highest CPPC performance is not the one in the _CPC
|
||||
table, so we need to expose it to sysfs. If boost is not active but
|
||||
supported, this maximum frequency will be larger than the one in
|
||||
In some ASICs, the highest CPPC performance is not the one in the ``_CPC``
|
||||
table, so we need to expose it to sysfs. If boost is not active, but
|
||||
still supported, this maximum frequency will be larger than the one in
|
||||
``cpuinfo``.
|
||||
This attribute is read-only.
|
||||
|
||||
``amd_pstate_lowest_nonlinear_freq``
|
||||
|
||||
The lowest non-linear CPPC CPU frequency that the driver is allowed to set
|
||||
in percent of the maximum supported CPPC performance level (Please see the
|
||||
The lowest non-linear CPPC CPU frequency that the driver is allowed to set,
|
||||
in percent of the maximum supported CPPC performance level. (Please see the
|
||||
lowest non-linear performance in `AMD CPPC Performance Capability
|
||||
<perf_cap_>`_).
|
||||
<perf_cap_>`_.)
|
||||
This attribute is read-only.
|
||||
|
||||
For other performance and frequency values, we can read them back from
|
||||
Other performance and frequency values can be read back from
|
||||
``/sys/devices/system/cpu/cpuX/acpi_cppc/``, see :ref:`cppc_sysfs`.
|
||||
|
||||
|
||||
``amd-pstate`` vs ``acpi-cpufreq``
|
||||
======================================
|
||||
|
||||
On majority of AMD platforms supported by ``acpi-cpufreq``, the ACPI tables
|
||||
provided by the platform firmware used for CPU performance scaling, but
|
||||
only provides 3 P-states on AMD processors.
|
||||
However, on modern AMD APU and CPU series, it provides the collaborative
|
||||
processor performance control according to ACPI protocol and customize this
|
||||
for AMD platforms. That is fine-grain and continuous frequency range
|
||||
On the majority of AMD platforms supported by ``acpi-cpufreq``, the ACPI tables
|
||||
provided by the platform firmware are used for CPU performance scaling, but
|
||||
only provide 3 P-states on AMD processors.
|
||||
However, on modern AMD APU and CPU series, hardware provides the Collaborative
|
||||
Processor Performance Control according to the ACPI protocol and customizes this
|
||||
for AMD platforms. That is, fine-grained and continuous frequency ranges
|
||||
instead of the legacy hardware P-states. ``amd-pstate`` is the kernel
|
||||
module which supports the new AMD P-States mechanism on most of future AMD
|
||||
platforms. The AMD P-States mechanism will be the more performance and energy
|
||||
module which supports the new AMD P-States mechanism on most of the future AMD
|
||||
platforms. The AMD P-States mechanism is the more performance and energy
|
||||
efficiency frequency management method on AMD processors.
|
||||
|
||||
Kernel Module Options for ``amd-pstate``
|
||||
|
@ -287,25 +286,25 @@ Kernel Module Options for ``amd-pstate``
|
|||
Use a module param (shared_mem) to enable related processors manually with
|
||||
**amd_pstate.shared_mem=1**.
|
||||
Due to the performance issue on the processors with `Shared Memory Support
|
||||
<perf_cap_>`_, so we disable it for the moment and will enable this by default
|
||||
once we address performance issue on this solution.
|
||||
<perf_cap_>`_, we disable it presently and will re-enable this by default
|
||||
once we address performance issue with this solution.
|
||||
|
||||
The way to check whether current processor is `Full MSR Support <perf_cap_>`_
|
||||
To check whether the current processor is using `Full MSR Support <perf_cap_>`_
|
||||
or `Shared Memory Support <perf_cap_>`_ : ::
|
||||
|
||||
ray@hr-test1:~$ lscpu | grep cppc
|
||||
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm
|
||||
|
||||
If CPU Flags have cppc, then this processor supports `Full MSR Support
|
||||
<perf_cap_>`_. Otherwise it supports `Shared Memory Support <perf_cap_>`_.
|
||||
If the CPU flags have ``cppc``, then this processor supports `Full MSR Support
|
||||
<perf_cap_>`_. Otherwise, it supports `Shared Memory Support <perf_cap_>`_.
|
||||
|
||||
|
||||
``cpupower`` tool support for ``amd-pstate``
|
||||
===============================================
|
||||
|
||||
``amd-pstate`` is supported on ``cpupower`` tool that can be used to dump the frequency
|
||||
information. And it is in progress to support more and more operations for new
|
||||
``amd-pstate`` module with this tool. ::
|
||||
``amd-pstate`` is supported by the ``cpupower`` tool, which can be used to dump
|
||||
frequency information. Development is in progress to support more and more
|
||||
operations for the new ``amd-pstate`` module with this tool. ::
|
||||
|
||||
root@hr-test1:/home/ray# cpupower frequency-info
|
||||
analyzing CPU 0:
|
||||
|
@ -336,10 +335,10 @@ Trace Events
|
|||
--------------
|
||||
|
||||
There are two static trace events that can be used for ``amd-pstate``
|
||||
diagnostics. One of them is the cpu_frequency trace event generally used
|
||||
diagnostics. One of them is the ``cpu_frequency`` trace event generally used
|
||||
by ``CPUFreq``, and the other one is the ``amd_pstate_perf`` trace event
|
||||
specific to ``amd-pstate``. The following sequence of shell commands can
|
||||
be used to enable them and see their output (if the kernel is generally
|
||||
be used to enable them and see their output (if the kernel is
|
||||
configured to support event tracing). ::
|
||||
|
||||
root@hr-test1:/home/ray# cd /sys/kernel/tracing/
|
||||
|
@ -364,7 +363,7 @@ configured to support event tracing). ::
|
|||
<idle>-0 [003] d.s.. 4995.980971: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=3 changed=false fast_switch=true
|
||||
<idle>-0 [011] d.s.. 4995.980996: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=11 changed=false fast_switch=true
|
||||
|
||||
The cpu_frequency trace event will be triggered either by the ``schedutil`` scaling
|
||||
The ``cpu_frequency`` trace event will be triggered either by the ``schedutil`` scaling
|
||||
governor (for the policies it is attached to), or by the ``CPUFreq`` core (for the
|
||||
policies with other scaling governors).
|
||||
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
Qualcomm Technologies, Inc. CPUFREQ Bindings
|
||||
|
||||
CPUFREQ HW is a hardware engine used by some Qualcomm Technologies, Inc. (QTI)
|
||||
SoCs to manage frequency in hardware. It is capable of controlling frequency
|
||||
for multiple clusters.
|
||||
|
||||
Properties:
|
||||
- compatible
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be "qcom,cpufreq-hw" or "qcom,cpufreq-epss".
|
||||
|
||||
- clocks
|
||||
Usage: required
|
||||
Value type: <phandle> From common clock binding.
|
||||
Definition: clock handle for XO clock and GPLL0 clock.
|
||||
|
||||
- clock-names
|
||||
Usage: required
|
||||
Value type: <string> From common clock binding.
|
||||
Definition: must be "xo", "alternate".
|
||||
|
||||
- reg
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Addresses and sizes for the memory of the HW bases in
|
||||
each frequency domain.
|
||||
- reg-names
|
||||
Usage: Optional
|
||||
Value type: <string>
|
||||
Definition: Frequency domain name i.e.
|
||||
"freq-domain0", "freq-domain1".
|
||||
|
||||
- #freq-domain-cells:
|
||||
Usage: required.
|
||||
Definition: Number of cells in a freqency domain specifier.
|
||||
|
||||
* Property qcom,freq-domain
|
||||
Devices supporting freq-domain must set their "qcom,freq-domain" property with
|
||||
phandle to a cpufreq_hw followed by the Domain ID(0/1) in the CPU DT node.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
Example 1: Dual-cluster, Quad-core per cluster. CPUs within a cluster switch
|
||||
DCVS state together.
|
||||
|
||||
/ {
|
||||
cpus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
|
||||
CPU0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x0>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_0>;
|
||||
qcom,freq-domain = <&cpufreq_hw 0>;
|
||||
L2_0: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
L3_0: l3-cache {
|
||||
compatible = "cache";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
CPU1: cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x100>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_100>;
|
||||
qcom,freq-domain = <&cpufreq_hw 0>;
|
||||
L2_100: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU2: cpu@200 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x200>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_200>;
|
||||
qcom,freq-domain = <&cpufreq_hw 0>;
|
||||
L2_200: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU3: cpu@300 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x300>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_300>;
|
||||
qcom,freq-domain = <&cpufreq_hw 0>;
|
||||
L2_300: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU4: cpu@400 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x400>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_400>;
|
||||
qcom,freq-domain = <&cpufreq_hw 1>;
|
||||
L2_400: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU5: cpu@500 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x500>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_500>;
|
||||
qcom,freq-domain = <&cpufreq_hw 1>;
|
||||
L2_500: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU6: cpu@600 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x600>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_600>;
|
||||
qcom,freq-domain = <&cpufreq_hw 1>;
|
||||
L2_600: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU7: cpu@700 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x700>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_700>;
|
||||
qcom,freq-domain = <&cpufreq_hw 1>;
|
||||
L2_700: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
cpufreq_hw: cpufreq@17d43000 {
|
||||
compatible = "qcom,cpufreq-hw";
|
||||
reg = <0x17d43000 0x1400>, <0x17d45800 0x1400>;
|
||||
reg-names = "freq-domain0", "freq-domain1";
|
||||
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>;
|
||||
clock-names = "xo", "alternate";
|
||||
|
||||
#freq-domain-cells = <1>;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/cpufreq/cpufreq-qcom-hw.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies, Inc. CPUFREQ
|
||||
|
||||
maintainers:
|
||||
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
description: |
|
||||
|
||||
CPUFREQ HW is a hardware engine used by some Qualcomm Technologies, Inc. (QTI)
|
||||
SoCs to manage frequency in hardware. It is capable of controlling frequency
|
||||
for multiple clusters.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: v1 of CPUFREQ HW
|
||||
items:
|
||||
- const: qcom,cpufreq-hw
|
||||
|
||||
- description: v2 of CPUFREQ HW (EPSS)
|
||||
items:
|
||||
- enum:
|
||||
- qcom,sm8250-cpufreq-epss
|
||||
- const: qcom,cpufreq-epss
|
||||
|
||||
reg:
|
||||
minItems: 2
|
||||
items:
|
||||
- description: Frequency domain 0 register region
|
||||
- description: Frequency domain 1 register region
|
||||
- description: Frequency domain 2 register region
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: freq-domain0
|
||||
- const: freq-domain1
|
||||
- const: freq-domain2
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: XO Clock
|
||||
- description: GPLL0 Clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: xo
|
||||
- const: alternate
|
||||
|
||||
'#freq-domain-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#freq-domain-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-sdm845.h>
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
|
||||
// Example 1: Dual-cluster, Quad-core per cluster. CPUs within a cluster
|
||||
// switch DCVS state together.
|
||||
cpus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
|
||||
CPU0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x0>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_0>;
|
||||
qcom,freq-domain = <&cpufreq_hw 0>;
|
||||
L2_0: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
L3_0: l3-cache {
|
||||
compatible = "cache";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
CPU1: cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x100>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_100>;
|
||||
qcom,freq-domain = <&cpufreq_hw 0>;
|
||||
L2_100: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU2: cpu@200 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x200>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_200>;
|
||||
qcom,freq-domain = <&cpufreq_hw 0>;
|
||||
L2_200: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU3: cpu@300 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x300>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_300>;
|
||||
qcom,freq-domain = <&cpufreq_hw 0>;
|
||||
L2_300: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU4: cpu@400 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x400>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_400>;
|
||||
qcom,freq-domain = <&cpufreq_hw 1>;
|
||||
L2_400: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU5: cpu@500 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x500>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_500>;
|
||||
qcom,freq-domain = <&cpufreq_hw 1>;
|
||||
L2_500: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU6: cpu@600 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x600>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_600>;
|
||||
qcom,freq-domain = <&cpufreq_hw 1>;
|
||||
L2_600: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU7: cpu@700 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo385";
|
||||
reg = <0x0 0x700>;
|
||||
enable-method = "psci";
|
||||
next-level-cache = <&L2_700>;
|
||||
qcom,freq-domain = <&cpufreq_hw 1>;
|
||||
L2_700: l2-cache {
|
||||
compatible = "cache";
|
||||
next-level-cache = <&L3_0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
cpufreq@17d43000 {
|
||||
compatible = "qcom,cpufreq-hw";
|
||||
reg = <0x17d43000 0x1400>, <0x17d45800 0x1400>;
|
||||
reg-names = "freq-domain0", "freq-domain1";
|
||||
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>;
|
||||
clock-names = "xo", "alternate";
|
||||
|
||||
#freq-domain-cells = <1>;
|
||||
};
|
||||
};
|
||||
...
|
|
@ -0,0 +1,166 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/cpufreq/qcom-cpufreq-nvmem.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies, Inc. NVMEM CPUFreq bindings
|
||||
|
||||
maintainers:
|
||||
- Ilia Lin <ilia.lin@kernel.org>
|
||||
|
||||
description: |
|
||||
In certain Qualcomm Technologies, Inc. SoCs such as QCS404, The CPU supply
|
||||
voltage is dynamically configured by Core Power Reduction (CPR) depending on
|
||||
current CPU frequency and efuse values.
|
||||
CPR provides a power domain with multiple levels that are selected depending
|
||||
on the CPU OPP in use. The CPUFreq driver sets the CPR power domain level
|
||||
according to the required OPPs defined in the CPU OPP tables.
|
||||
|
||||
select:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,qcs404
|
||||
required:
|
||||
- compatible
|
||||
|
||||
properties:
|
||||
cpus:
|
||||
type: object
|
||||
|
||||
patternProperties:
|
||||
'cpu@[0-9a-f]+':
|
||||
type: object
|
||||
|
||||
properties:
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
power-domain-names:
|
||||
items:
|
||||
- const: cpr
|
||||
|
||||
required:
|
||||
- power-domains
|
||||
- power-domain-names
|
||||
|
||||
patternProperties:
|
||||
'^opp-table(-[a-z0-9]+)?$':
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
const: operating-points-v2-kryo-cpu
|
||||
then:
|
||||
patternProperties:
|
||||
'^opp-?[0-9]+$':
|
||||
required:
|
||||
- required-opps
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
examples:
|
||||
- |
|
||||
/ {
|
||||
model = "Qualcomm Technologies, Inc. QCS404";
|
||||
compatible = "qcom,qcs404";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
CPU0: cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53";
|
||||
reg = <0x100>;
|
||||
enable-method = "psci";
|
||||
cpu-idle-states = <&CPU_SLEEP_0>;
|
||||
next-level-cache = <&L2_0>;
|
||||
#cooling-cells = <2>;
|
||||
clocks = <&apcs_glb>;
|
||||
operating-points-v2 = <&cpu_opp_table>;
|
||||
power-domains = <&cpr>;
|
||||
power-domain-names = "cpr";
|
||||
};
|
||||
|
||||
CPU1: cpu@101 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53";
|
||||
reg = <0x101>;
|
||||
enable-method = "psci";
|
||||
cpu-idle-states = <&CPU_SLEEP_0>;
|
||||
next-level-cache = <&L2_0>;
|
||||
#cooling-cells = <2>;
|
||||
clocks = <&apcs_glb>;
|
||||
operating-points-v2 = <&cpu_opp_table>;
|
||||
power-domains = <&cpr>;
|
||||
power-domain-names = "cpr";
|
||||
};
|
||||
|
||||
CPU2: cpu@102 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53";
|
||||
reg = <0x102>;
|
||||
enable-method = "psci";
|
||||
cpu-idle-states = <&CPU_SLEEP_0>;
|
||||
next-level-cache = <&L2_0>;
|
||||
#cooling-cells = <2>;
|
||||
clocks = <&apcs_glb>;
|
||||
operating-points-v2 = <&cpu_opp_table>;
|
||||
power-domains = <&cpr>;
|
||||
power-domain-names = "cpr";
|
||||
};
|
||||
|
||||
CPU3: cpu@103 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53";
|
||||
reg = <0x103>;
|
||||
enable-method = "psci";
|
||||
cpu-idle-states = <&CPU_SLEEP_0>;
|
||||
next-level-cache = <&L2_0>;
|
||||
#cooling-cells = <2>;
|
||||
clocks = <&apcs_glb>;
|
||||
operating-points-v2 = <&cpu_opp_table>;
|
||||
power-domains = <&cpr>;
|
||||
power-domain-names = "cpr";
|
||||
};
|
||||
};
|
||||
|
||||
cpu_opp_table: opp-table-cpu {
|
||||
compatible = "operating-points-v2-kryo-cpu";
|
||||
opp-shared;
|
||||
|
||||
opp-1094400000 {
|
||||
opp-hz = /bits/ 64 <1094400000>;
|
||||
required-opps = <&cpr_opp1>;
|
||||
};
|
||||
opp-1248000000 {
|
||||
opp-hz = /bits/ 64 <1248000000>;
|
||||
required-opps = <&cpr_opp2>;
|
||||
};
|
||||
opp-1401600000 {
|
||||
opp-hz = /bits/ 64 <1401600000>;
|
||||
required-opps = <&cpr_opp3>;
|
||||
};
|
||||
};
|
||||
|
||||
cpr_opp_table: opp-table-cpr {
|
||||
compatible = "operating-points-v2-qcom-level";
|
||||
|
||||
cpr_opp1: opp1 {
|
||||
opp-level = <1>;
|
||||
qcom,opp-fuse-level = <1>;
|
||||
};
|
||||
cpr_opp2: opp2 {
|
||||
opp-level = <2>;
|
||||
qcom,opp-fuse-level = <2>;
|
||||
};
|
||||
cpr_opp3: opp3 {
|
||||
opp-level = <3>;
|
||||
qcom,opp-fuse-level = <3>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -51,10 +51,16 @@ additionalProperties: true
|
|||
|
||||
examples:
|
||||
- |
|
||||
performance: performance-controller@12340000 {
|
||||
compatible = "qcom,cpufreq-hw";
|
||||
reg = <0x12340000 0x1000>;
|
||||
#performance-domain-cells = <1>;
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
performance: performance-controller@11bc00 {
|
||||
compatible = "mediatek,cpufreq-hw";
|
||||
reg = <0 0x0011bc10 0 0x120>, <0 0x0011bd30 0 0x120>;
|
||||
|
||||
#performance-domain-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
// The node above defines a performance controller that is a performance
|
||||
|
|
|
@ -93,6 +93,21 @@ patternProperties:
|
|||
minItems: 1
|
||||
maxItems: 8 # Should be enough regulators
|
||||
|
||||
opp-microwatt:
|
||||
description: |
|
||||
The power for the OPP in micro-Watts.
|
||||
|
||||
Entries for multiple regulators shall be provided in the same field
|
||||
separated by angular brackets <>. If current values aren't required
|
||||
for a regulator, then it shall be filled with 0. If power values
|
||||
aren't required for any of the regulators, then this field is not
|
||||
required. The OPP binding doesn't provide any provisions to relate the
|
||||
values to their power supplies or the order in which the supplies need
|
||||
to be configured and that is left for the implementation specific
|
||||
binding.
|
||||
minItems: 1
|
||||
maxItems: 8 # Should be enough regulators
|
||||
|
||||
opp-level:
|
||||
description:
|
||||
A value representing the performance level of the device.
|
||||
|
@ -205,6 +220,14 @@ patternProperties:
|
|||
minItems: 1
|
||||
maxItems: 8 # Should be enough regulators
|
||||
|
||||
'^opp-microwatt':
|
||||
description:
|
||||
Named opp-microwatt property. Similar to opp-microamp property,
|
||||
but for microwatt instead.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 1
|
||||
maxItems: 8 # Should be enough regulators
|
||||
|
||||
dependencies:
|
||||
opp-avg-kBps: [ opp-peak-kBps ]
|
||||
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/opp/opp-v2-kryo-cpu.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies, Inc. NVMEM OPP bindings
|
||||
|
||||
maintainers:
|
||||
- Ilia Lin <ilia.lin@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: opp-v2-base.yaml#
|
||||
|
||||
description: |
|
||||
In certain Qualcomm Technologies, Inc. SoCs like APQ8096 and MSM8996,
|
||||
the CPU frequencies subset and voltage value of each OPP varies based on
|
||||
the silicon variant in use.
|
||||
Qualcomm Technologies, Inc. Process Voltage Scaling Tables
|
||||
defines the voltage and frequency value based on the msm-id in SMEM
|
||||
and speedbin blown in the efuse combination.
|
||||
The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC
|
||||
to provide the OPP framework with required information (existing HW bitmap).
|
||||
This is used to determine the voltage and frequency value for each OPP of
|
||||
operating-points-v2 table when it is parsed by the OPP framework.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: operating-points-v2-kryo-cpu
|
||||
|
||||
nvmem-cells:
|
||||
description: |
|
||||
A phandle pointing to a nvmem-cells node representing the
|
||||
efuse registers that has information about the
|
||||
speedbin that is used to select the right frequency/voltage
|
||||
value pair.
|
||||
|
||||
opp-shared: true
|
||||
|
||||
patternProperties:
|
||||
'^opp-?[0-9]+$':
|
||||
type: object
|
||||
|
||||
properties:
|
||||
opp-hz: true
|
||||
|
||||
opp-microvolt: true
|
||||
|
||||
opp-supported-hw:
|
||||
description: |
|
||||
A single 32 bit bitmap value, representing compatible HW.
|
||||
Bitmap:
|
||||
0: MSM8996 V3, speedbin 0
|
||||
1: MSM8996 V3, speedbin 1
|
||||
2: MSM8996 V3, speedbin 2
|
||||
3: unused
|
||||
4: MSM8996 SG, speedbin 0
|
||||
5: MSM8996 SG, speedbin 1
|
||||
6: MSM8996 SG, speedbin 2
|
||||
7-31: unused
|
||||
maximum: 0x77
|
||||
|
||||
clock-latency-ns: true
|
||||
|
||||
required-opps: true
|
||||
|
||||
required:
|
||||
- opp-hz
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
if:
|
||||
required:
|
||||
- nvmem-cells
|
||||
then:
|
||||
patternProperties:
|
||||
'^opp-?[0-9]+$':
|
||||
required:
|
||||
- opp-supported-hw
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
/ {
|
||||
model = "Qualcomm Technologies, Inc. DB820c";
|
||||
compatible = "arrow,apq8096-db820c", "qcom,apq8096-sbc", "qcom,apq8096";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
cpus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
|
||||
CPU0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x0>;
|
||||
enable-method = "psci";
|
||||
cpu-idle-states = <&CPU_SLEEP_0>;
|
||||
capacity-dmips-mhz = <1024>;
|
||||
clocks = <&kryocc 0>;
|
||||
operating-points-v2 = <&cluster0_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_0>;
|
||||
L2_0: l2-cache {
|
||||
compatible = "cache";
|
||||
cache-level = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x1>;
|
||||
enable-method = "psci";
|
||||
cpu-idle-states = <&CPU_SLEEP_0>;
|
||||
capacity-dmips-mhz = <1024>;
|
||||
clocks = <&kryocc 0>;
|
||||
operating-points-v2 = <&cluster0_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_0>;
|
||||
};
|
||||
|
||||
CPU2: cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x100>;
|
||||
enable-method = "psci";
|
||||
cpu-idle-states = <&CPU_SLEEP_0>;
|
||||
capacity-dmips-mhz = <1024>;
|
||||
clocks = <&kryocc 1>;
|
||||
operating-points-v2 = <&cluster1_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_1>;
|
||||
L2_1: l2-cache {
|
||||
compatible = "cache";
|
||||
cache-level = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU3: cpu@101 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x101>;
|
||||
enable-method = "psci";
|
||||
cpu-idle-states = <&CPU_SLEEP_0>;
|
||||
capacity-dmips-mhz = <1024>;
|
||||
clocks = <&kryocc 1>;
|
||||
operating-points-v2 = <&cluster1_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_1>;
|
||||
};
|
||||
|
||||
cpu-map {
|
||||
cluster0 {
|
||||
core0 {
|
||||
cpu = <&CPU0>;
|
||||
};
|
||||
|
||||
core1 {
|
||||
cpu = <&CPU1>;
|
||||
};
|
||||
};
|
||||
|
||||
cluster1 {
|
||||
core0 {
|
||||
cpu = <&CPU2>;
|
||||
};
|
||||
|
||||
core1 {
|
||||
cpu = <&CPU3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cluster0_opp: opp-table-0 {
|
||||
compatible = "operating-points-v2-kryo-cpu";
|
||||
nvmem-cells = <&speedbin_efuse>;
|
||||
opp-shared;
|
||||
|
||||
opp-307200000 {
|
||||
opp-hz = /bits/ 64 <307200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x77>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1593600000 {
|
||||
opp-hz = /bits/ 64 <1593600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x71>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2188800000 {
|
||||
opp-hz = /bits/ 64 <2188800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x10>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
};
|
||||
|
||||
cluster1_opp: opp-table-1 {
|
||||
compatible = "operating-points-v2-kryo-cpu";
|
||||
nvmem-cells = <&speedbin_efuse>;
|
||||
opp-shared;
|
||||
|
||||
opp-307200000 {
|
||||
opp-hz = /bits/ 64 <307200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x77>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1593600000 {
|
||||
opp-hz = /bits/ 64 <1593600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2150400000 {
|
||||
opp-hz = /bits/ 64 <2150400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x31>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2342400000 {
|
||||
opp-hz = /bits/ 64 <2342400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x10>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
};
|
||||
|
||||
smem {
|
||||
compatible = "qcom,smem";
|
||||
memory-region = <&smem_mem>;
|
||||
hwlocks = <&tcsr_mutex 3>;
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
qfprom: qfprom@74000 {
|
||||
compatible = "qcom,msm8996-qfprom", "qcom,qfprom";
|
||||
reg = <0x00074000 0x8ff>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
speedbin_efuse: speedbin@133 {
|
||||
reg = <0x133 0x1>;
|
||||
bits = <5 3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,60 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/opp/opp-v2-qcom-level.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm OPP bindings to describe OPP nodes.
|
||||
|
||||
maintainers:
|
||||
- Niklas Cassel <nks@flawful.org>
|
||||
|
||||
allOf:
|
||||
- $ref: opp-v2-base.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: operating-points-v2-qcom-level
|
||||
|
||||
patternProperties:
|
||||
'^opp-?[0-9]+$':
|
||||
type: object
|
||||
|
||||
properties:
|
||||
opp-level: true
|
||||
|
||||
qcom,opp-fuse-level:
|
||||
description: |
|
||||
A positive value representing the fuse corner/level associated with
|
||||
this OPP node. Sometimes several corners/levels shares a certain fuse
|
||||
corner/level. A fuse corner/level contains e.g. ref uV, min uV,
|
||||
and max uV.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
required:
|
||||
- opp-level
|
||||
- qcom,opp-fuse-level
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
cpr_opp_table: opp-table-cpr {
|
||||
compatible = "operating-points-v2-qcom-level";
|
||||
|
||||
cpr_opp1: opp1 {
|
||||
opp-level = <1>;
|
||||
qcom,opp-fuse-level = <1>;
|
||||
};
|
||||
cpr_opp2: opp2 {
|
||||
opp-level = <2>;
|
||||
qcom,opp-fuse-level = <2>;
|
||||
};
|
||||
cpr_opp3: opp3 {
|
||||
opp-level = <3>;
|
||||
qcom,opp-fuse-level = <3>;
|
||||
};
|
||||
};
|
|
@ -1,796 +0,0 @@
|
|||
Qualcomm Technologies, Inc. NVMEM CPUFreq and OPP bindings
|
||||
===================================
|
||||
|
||||
In Certain Qualcomm Technologies, Inc. SoCs like apq8096 and msm8996,
|
||||
the CPU frequencies subset and voltage value of each OPP varies based on
|
||||
the silicon variant in use.
|
||||
Qualcomm Technologies, Inc. Process Voltage Scaling Tables
|
||||
defines the voltage and frequency value based on the msm-id in SMEM
|
||||
and speedbin blown in the efuse combination.
|
||||
The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC
|
||||
to provide the OPP framework with required information (existing HW bitmap).
|
||||
This is used to determine the voltage and frequency value for each OPP of
|
||||
operating-points-v2 table when it is parsed by the OPP framework.
|
||||
|
||||
Required properties:
|
||||
--------------------
|
||||
In 'cpu' nodes:
|
||||
- operating-points-v2: Phandle to the operating-points-v2 table to use.
|
||||
|
||||
In 'operating-points-v2' table:
|
||||
- compatible: Should be
|
||||
- 'operating-points-v2-kryo-cpu' for apq8096, msm8996, msm8974,
|
||||
apq8064, ipq8064, msm8960 and ipq8074.
|
||||
|
||||
Optional properties:
|
||||
--------------------
|
||||
In 'cpu' nodes:
|
||||
- power-domains: A phandle pointing to the PM domain specifier which provides
|
||||
the performance states available for active state management.
|
||||
Please refer to the power-domains bindings
|
||||
Documentation/devicetree/bindings/power/power_domain.txt
|
||||
and also examples below.
|
||||
- power-domain-names: Should be
|
||||
- 'cpr' for qcs404.
|
||||
|
||||
In 'operating-points-v2' table:
|
||||
- nvmem-cells: A phandle pointing to a nvmem-cells node representing the
|
||||
efuse registers that has information about the
|
||||
speedbin that is used to select the right frequency/voltage
|
||||
value pair.
|
||||
Please refer the for nvmem-cells
|
||||
bindings Documentation/devicetree/bindings/nvmem/nvmem.txt
|
||||
and also examples below.
|
||||
|
||||
In every OPP node:
|
||||
- opp-supported-hw: A single 32 bit bitmap value, representing compatible HW.
|
||||
Bitmap:
|
||||
0: MSM8996 V3, speedbin 0
|
||||
1: MSM8996 V3, speedbin 1
|
||||
2: MSM8996 V3, speedbin 2
|
||||
3: unused
|
||||
4: MSM8996 SG, speedbin 0
|
||||
5: MSM8996 SG, speedbin 1
|
||||
6: MSM8996 SG, speedbin 2
|
||||
7-31: unused
|
||||
|
||||
Example 1:
|
||||
---------
|
||||
|
||||
cpus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
|
||||
CPU0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x0>;
|
||||
enable-method = "psci";
|
||||
clocks = <&kryocc 0>;
|
||||
cpu-supply = <&pm8994_s11_saw>;
|
||||
operating-points-v2 = <&cluster0_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_0>;
|
||||
L2_0: l2-cache {
|
||||
compatible = "cache";
|
||||
cache-level = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x1>;
|
||||
enable-method = "psci";
|
||||
clocks = <&kryocc 0>;
|
||||
cpu-supply = <&pm8994_s11_saw>;
|
||||
operating-points-v2 = <&cluster0_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_0>;
|
||||
};
|
||||
|
||||
CPU2: cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x100>;
|
||||
enable-method = "psci";
|
||||
clocks = <&kryocc 1>;
|
||||
cpu-supply = <&pm8994_s11_saw>;
|
||||
operating-points-v2 = <&cluster1_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_1>;
|
||||
L2_1: l2-cache {
|
||||
compatible = "cache";
|
||||
cache-level = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
CPU3: cpu@101 {
|
||||
device_type = "cpu";
|
||||
compatible = "qcom,kryo";
|
||||
reg = <0x0 0x101>;
|
||||
enable-method = "psci";
|
||||
clocks = <&kryocc 1>;
|
||||
cpu-supply = <&pm8994_s11_saw>;
|
||||
operating-points-v2 = <&cluster1_opp>;
|
||||
#cooling-cells = <2>;
|
||||
next-level-cache = <&L2_1>;
|
||||
};
|
||||
|
||||
cpu-map {
|
||||
cluster0 {
|
||||
core0 {
|
||||
cpu = <&CPU0>;
|
||||
};
|
||||
|
||||
core1 {
|
||||
cpu = <&CPU1>;
|
||||
};
|
||||
};
|
||||
|
||||
cluster1 {
|
||||
core0 {
|
||||
cpu = <&CPU2>;
|
||||
};
|
||||
|
||||
core1 {
|
||||
cpu = <&CPU3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cluster0_opp: opp_table0 {
|
||||
compatible = "operating-points-v2-kryo-cpu";
|
||||
nvmem-cells = <&speedbin_efuse>;
|
||||
opp-shared;
|
||||
|
||||
opp-307200000 {
|
||||
opp-hz = /bits/ 64 <307200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x77>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-384000000 {
|
||||
opp-hz = /bits/ 64 <384000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-422400000 {
|
||||
opp-hz = /bits/ 64 <422400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-460800000 {
|
||||
opp-hz = /bits/ 64 <460800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-480000000 {
|
||||
opp-hz = /bits/ 64 <480000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-537600000 {
|
||||
opp-hz = /bits/ 64 <537600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-556800000 {
|
||||
opp-hz = /bits/ 64 <556800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-614400000 {
|
||||
opp-hz = /bits/ 64 <614400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-652800000 {
|
||||
opp-hz = /bits/ 64 <652800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-691200000 {
|
||||
opp-hz = /bits/ 64 <691200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-729600000 {
|
||||
opp-hz = /bits/ 64 <729600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-768000000 {
|
||||
opp-hz = /bits/ 64 <768000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-844800000 {
|
||||
opp-hz = /bits/ 64 <844800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x77>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-902400000 {
|
||||
opp-hz = /bits/ 64 <902400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-960000000 {
|
||||
opp-hz = /bits/ 64 <960000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-979200000 {
|
||||
opp-hz = /bits/ 64 <979200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1036800000 {
|
||||
opp-hz = /bits/ 64 <1036800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1056000000 {
|
||||
opp-hz = /bits/ 64 <1056000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1113600000 {
|
||||
opp-hz = /bits/ 64 <1113600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1132800000 {
|
||||
opp-hz = /bits/ 64 <1132800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1190400000 {
|
||||
opp-hz = /bits/ 64 <1190400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1209600000 {
|
||||
opp-hz = /bits/ 64 <1209600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1228800000 {
|
||||
opp-hz = /bits/ 64 <1228800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1286400000 {
|
||||
opp-hz = /bits/ 64 <1286400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1324800000 {
|
||||
opp-hz = /bits/ 64 <1324800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x5>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1363200000 {
|
||||
opp-hz = /bits/ 64 <1363200000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x72>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1401600000 {
|
||||
opp-hz = /bits/ 64 <1401600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x5>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1440000000 {
|
||||
opp-hz = /bits/ 64 <1440000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1478400000 {
|
||||
opp-hz = /bits/ 64 <1478400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x1>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1497600000 {
|
||||
opp-hz = /bits/ 64 <1497600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x4>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1516800000 {
|
||||
opp-hz = /bits/ 64 <1516800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1593600000 {
|
||||
opp-hz = /bits/ 64 <1593600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x71>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1996800000 {
|
||||
opp-hz = /bits/ 64 <1996800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x20>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2188800000 {
|
||||
opp-hz = /bits/ 64 <2188800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x10>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
};
|
||||
|
||||
cluster1_opp: opp_table1 {
|
||||
compatible = "operating-points-v2-kryo-cpu";
|
||||
nvmem-cells = <&speedbin_efuse>;
|
||||
opp-shared;
|
||||
|
||||
opp-307200000 {
|
||||
opp-hz = /bits/ 64 <307200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x77>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-384000000 {
|
||||
opp-hz = /bits/ 64 <384000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-403200000 {
|
||||
opp-hz = /bits/ 64 <403200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-460800000 {
|
||||
opp-hz = /bits/ 64 <460800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-480000000 {
|
||||
opp-hz = /bits/ 64 <480000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-537600000 {
|
||||
opp-hz = /bits/ 64 <537600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-556800000 {
|
||||
opp-hz = /bits/ 64 <556800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-614400000 {
|
||||
opp-hz = /bits/ 64 <614400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-652800000 {
|
||||
opp-hz = /bits/ 64 <652800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-691200000 {
|
||||
opp-hz = /bits/ 64 <691200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-729600000 {
|
||||
opp-hz = /bits/ 64 <729600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-748800000 {
|
||||
opp-hz = /bits/ 64 <748800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-806400000 {
|
||||
opp-hz = /bits/ 64 <806400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-825600000 {
|
||||
opp-hz = /bits/ 64 <825600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-883200000 {
|
||||
opp-hz = /bits/ 64 <883200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-902400000 {
|
||||
opp-hz = /bits/ 64 <902400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-940800000 {
|
||||
opp-hz = /bits/ 64 <940800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-979200000 {
|
||||
opp-hz = /bits/ 64 <979200000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1036800000 {
|
||||
opp-hz = /bits/ 64 <1036800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1056000000 {
|
||||
opp-hz = /bits/ 64 <1056000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1113600000 {
|
||||
opp-hz = /bits/ 64 <1113600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1132800000 {
|
||||
opp-hz = /bits/ 64 <1132800000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1190400000 {
|
||||
opp-hz = /bits/ 64 <1190400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1209600000 {
|
||||
opp-hz = /bits/ 64 <1209600000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1248000000 {
|
||||
opp-hz = /bits/ 64 <1248000000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1286400000 {
|
||||
opp-hz = /bits/ 64 <1286400000>;
|
||||
opp-microvolt = <905000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1324800000 {
|
||||
opp-hz = /bits/ 64 <1324800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1363200000 {
|
||||
opp-hz = /bits/ 64 <1363200000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1401600000 {
|
||||
opp-hz = /bits/ 64 <1401600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1440000000 {
|
||||
opp-hz = /bits/ 64 <1440000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1478400000 {
|
||||
opp-hz = /bits/ 64 <1478400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1516800000 {
|
||||
opp-hz = /bits/ 64 <1516800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1555200000 {
|
||||
opp-hz = /bits/ 64 <1555200000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1593600000 {
|
||||
opp-hz = /bits/ 64 <1593600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1632000000 {
|
||||
opp-hz = /bits/ 64 <1632000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1670400000 {
|
||||
opp-hz = /bits/ 64 <1670400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1708800000 {
|
||||
opp-hz = /bits/ 64 <1708800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1747200000 {
|
||||
opp-hz = /bits/ 64 <1747200000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x70>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1785600000 {
|
||||
opp-hz = /bits/ 64 <1785600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x7>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1804800000 {
|
||||
opp-hz = /bits/ 64 <1804800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x6>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1824000000 {
|
||||
opp-hz = /bits/ 64 <1824000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x71>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1900800000 {
|
||||
opp-hz = /bits/ 64 <1900800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x74>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1920000000 {
|
||||
opp-hz = /bits/ 64 <1920000000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x1>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1977600000 {
|
||||
opp-hz = /bits/ 64 <1977600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x30>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-1996800000 {
|
||||
opp-hz = /bits/ 64 <1996800000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x1>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2054400000 {
|
||||
opp-hz = /bits/ 64 <2054400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x30>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2073600000 {
|
||||
opp-hz = /bits/ 64 <2073600000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x1>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2150400000 {
|
||||
opp-hz = /bits/ 64 <2150400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x31>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2246400000 {
|
||||
opp-hz = /bits/ 64 <2246400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x10>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
opp-2342400000 {
|
||||
opp-hz = /bits/ 64 <2342400000>;
|
||||
opp-microvolt = <1140000 905000 1140000>;
|
||||
opp-supported-hw = <0x10>;
|
||||
clock-latency-ns = <200000>;
|
||||
};
|
||||
};
|
||||
|
||||
....
|
||||
|
||||
reserved-memory {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
....
|
||||
smem_mem: smem-mem@86000000 {
|
||||
reg = <0x0 0x86000000 0x0 0x200000>;
|
||||
no-map;
|
||||
};
|
||||
....
|
||||
};
|
||||
|
||||
smem {
|
||||
compatible = "qcom,smem";
|
||||
memory-region = <&smem_mem>;
|
||||
hwlocks = <&tcsr_mutex 3>;
|
||||
};
|
||||
|
||||
soc {
|
||||
....
|
||||
qfprom: qfprom@74000 {
|
||||
compatible = "qcom,qfprom";
|
||||
reg = <0x00074000 0x8ff>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
....
|
||||
speedbin_efuse: speedbin@133 {
|
||||
reg = <0x133 0x1>;
|
||||
bits = <5 3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Example 2:
|
||||
---------
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
CPU0: cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53";
|
||||
reg = <0x100>;
|
||||
....
|
||||
clocks = <&apcs_glb>;
|
||||
operating-points-v2 = <&cpu_opp_table>;
|
||||
power-domains = <&cpr>;
|
||||
power-domain-names = "cpr";
|
||||
};
|
||||
|
||||
CPU1: cpu@101 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53";
|
||||
reg = <0x101>;
|
||||
....
|
||||
clocks = <&apcs_glb>;
|
||||
operating-points-v2 = <&cpu_opp_table>;
|
||||
power-domains = <&cpr>;
|
||||
power-domain-names = "cpr";
|
||||
};
|
||||
|
||||
CPU2: cpu@102 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53";
|
||||
reg = <0x102>;
|
||||
....
|
||||
clocks = <&apcs_glb>;
|
||||
operating-points-v2 = <&cpu_opp_table>;
|
||||
power-domains = <&cpr>;
|
||||
power-domain-names = "cpr";
|
||||
};
|
||||
|
||||
CPU3: cpu@103 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a53";
|
||||
reg = <0x103>;
|
||||
....
|
||||
clocks = <&apcs_glb>;
|
||||
operating-points-v2 = <&cpu_opp_table>;
|
||||
power-domains = <&cpr>;
|
||||
power-domain-names = "cpr";
|
||||
};
|
||||
};
|
||||
|
||||
cpu_opp_table: cpu-opp-table {
|
||||
compatible = "operating-points-v2-kryo-cpu";
|
||||
opp-shared;
|
||||
|
||||
opp-1094400000 {
|
||||
opp-hz = /bits/ 64 <1094400000>;
|
||||
required-opps = <&cpr_opp1>;
|
||||
};
|
||||
opp-1248000000 {
|
||||
opp-hz = /bits/ 64 <1248000000>;
|
||||
required-opps = <&cpr_opp2>;
|
||||
};
|
||||
opp-1401600000 {
|
||||
opp-hz = /bits/ 64 <1401600000>;
|
||||
required-opps = <&cpr_opp3>;
|
||||
};
|
||||
};
|
||||
|
||||
cpr_opp_table: cpr-opp-table {
|
||||
compatible = "operating-points-v2-qcom-level";
|
||||
|
||||
cpr_opp1: opp1 {
|
||||
opp-level = <1>;
|
||||
qcom,opp-fuse-level = <1>;
|
||||
};
|
||||
cpr_opp2: opp2 {
|
||||
opp-level = <2>;
|
||||
qcom,opp-fuse-level = <2>;
|
||||
};
|
||||
cpr_opp3: opp3 {
|
||||
opp-level = <3>;
|
||||
qcom,opp-fuse-level = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
....
|
||||
|
||||
soc {
|
||||
....
|
||||
cpr: power-controller@b018000 {
|
||||
compatible = "qcom,qcs404-cpr", "qcom,cpr";
|
||||
reg = <0x0b018000 0x1000>;
|
||||
....
|
||||
vdd-apc-supply = <&pms405_s3>;
|
||||
#power-domain-cells = <0>;
|
||||
operating-points-v2 = <&cpr_opp_table>;
|
||||
....
|
||||
};
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
Qualcomm OPP bindings to describe OPP nodes
|
||||
|
||||
The bindings are based on top of the operating-points-v2 bindings
|
||||
described in Documentation/devicetree/bindings/opp/opp-v2-base.yaml
|
||||
Additional properties are described below.
|
||||
|
||||
* OPP Table Node
|
||||
|
||||
Required properties:
|
||||
- compatible: Allow OPPs to express their compatibility. It should be:
|
||||
"operating-points-v2-qcom-level"
|
||||
|
||||
* OPP Node
|
||||
|
||||
Required properties:
|
||||
- qcom,opp-fuse-level: A positive value representing the fuse corner/level
|
||||
associated with this OPP node. Sometimes several corners/levels shares
|
||||
a certain fuse corner/level. A fuse corner/level contains e.g. ref uV,
|
||||
min uV, and max uV.
|
|
@ -1,130 +0,0 @@
|
|||
QCOM CPR (Core Power Reduction)
|
||||
|
||||
CPR (Core Power Reduction) is a technology to reduce core power on a CPU
|
||||
or other device. Each OPP of a device corresponds to a "corner" that has
|
||||
a range of valid voltages for a particular frequency. While the device is
|
||||
running at a particular frequency, CPR monitors dynamic factors such as
|
||||
temperature, etc. and suggests adjustments to the voltage to save power
|
||||
and meet silicon characteristic requirements.
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: should be "qcom,qcs404-cpr", "qcom,cpr" for qcs404
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: base address and size of the rbcpr register region
|
||||
|
||||
- interrupts:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: should specify the CPR interrupt
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: phandle to the reference clock
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: must be "ref"
|
||||
|
||||
- vdd-apc-supply:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: phandle to the vdd-apc-supply regulator
|
||||
|
||||
- #power-domain-cells:
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: should be 0
|
||||
|
||||
- operating-points-v2:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: A phandle to the OPP table containing the
|
||||
performance states supported by the CPR
|
||||
power domain
|
||||
|
||||
- acc-syscon:
|
||||
Usage: optional
|
||||
Value type: <phandle>
|
||||
Definition: phandle to syscon for writing ACC settings
|
||||
|
||||
- nvmem-cells:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: phandle to nvmem cells containing the data
|
||||
that makes up a fuse corner, for each fuse corner.
|
||||
As well as the CPR fuse revision.
|
||||
|
||||
- nvmem-cell-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: should be "cpr_quotient_offset1", "cpr_quotient_offset2",
|
||||
"cpr_quotient_offset3", "cpr_init_voltage1",
|
||||
"cpr_init_voltage2", "cpr_init_voltage3", "cpr_quotient1",
|
||||
"cpr_quotient2", "cpr_quotient3", "cpr_ring_osc1",
|
||||
"cpr_ring_osc2", "cpr_ring_osc3", "cpr_fuse_revision"
|
||||
for qcs404.
|
||||
|
||||
Example:
|
||||
|
||||
cpr_opp_table: cpr-opp-table {
|
||||
compatible = "operating-points-v2-qcom-level";
|
||||
|
||||
cpr_opp1: opp1 {
|
||||
opp-level = <1>;
|
||||
qcom,opp-fuse-level = <1>;
|
||||
};
|
||||
cpr_opp2: opp2 {
|
||||
opp-level = <2>;
|
||||
qcom,opp-fuse-level = <2>;
|
||||
};
|
||||
cpr_opp3: opp3 {
|
||||
opp-level = <3>;
|
||||
qcom,opp-fuse-level = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
power-controller@b018000 {
|
||||
compatible = "qcom,qcs404-cpr", "qcom,cpr";
|
||||
reg = <0x0b018000 0x1000>;
|
||||
interrupts = <0 15 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&xo_board>;
|
||||
clock-names = "ref";
|
||||
vdd-apc-supply = <&pms405_s3>;
|
||||
#power-domain-cells = <0>;
|
||||
operating-points-v2 = <&cpr_opp_table>;
|
||||
acc-syscon = <&tcsr>;
|
||||
|
||||
nvmem-cells = <&cpr_efuse_quot_offset1>,
|
||||
<&cpr_efuse_quot_offset2>,
|
||||
<&cpr_efuse_quot_offset3>,
|
||||
<&cpr_efuse_init_voltage1>,
|
||||
<&cpr_efuse_init_voltage2>,
|
||||
<&cpr_efuse_init_voltage3>,
|
||||
<&cpr_efuse_quot1>,
|
||||
<&cpr_efuse_quot2>,
|
||||
<&cpr_efuse_quot3>,
|
||||
<&cpr_efuse_ring1>,
|
||||
<&cpr_efuse_ring2>,
|
||||
<&cpr_efuse_ring3>,
|
||||
<&cpr_efuse_revision>;
|
||||
nvmem-cell-names = "cpr_quotient_offset1",
|
||||
"cpr_quotient_offset2",
|
||||
"cpr_quotient_offset3",
|
||||
"cpr_init_voltage1",
|
||||
"cpr_init_voltage2",
|
||||
"cpr_init_voltage3",
|
||||
"cpr_quotient1",
|
||||
"cpr_quotient2",
|
||||
"cpr_quotient3",
|
||||
"cpr_ring_osc1",
|
||||
"cpr_ring_osc2",
|
||||
"cpr_ring_osc3",
|
||||
"cpr_fuse_revision";
|
||||
};
|
|
@ -0,0 +1,160 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/avs/qcom,cpr.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Core Power Reduction (CPR) bindings
|
||||
|
||||
maintainers:
|
||||
- Niklas Cassel <nks@flawful.org>
|
||||
|
||||
description: |
|
||||
CPR (Core Power Reduction) is a technology to reduce core power on a CPU
|
||||
or other device. Each OPP of a device corresponds to a "corner" that has
|
||||
a range of valid voltages for a particular frequency. While the device is
|
||||
running at a particular frequency, CPR monitors dynamic factors such as
|
||||
temperature, etc. and suggests adjustments to the voltage to save power
|
||||
and meet silicon characteristic requirements.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- qcom,qcs404-cpr
|
||||
- const: qcom,cpr
|
||||
|
||||
reg:
|
||||
description: Base address and size of the RBCPR register region.
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Reference clock.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref
|
||||
|
||||
vdd-apc-supply:
|
||||
description: APC regulator supply.
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 0
|
||||
|
||||
operating-points-v2:
|
||||
description: |
|
||||
A phandle to the OPP table containing the performance states
|
||||
supported by the CPR power domain.
|
||||
|
||||
acc-syscon:
|
||||
description: A phandle to the syscon used for writing ACC settings.
|
||||
|
||||
nvmem-cells:
|
||||
items:
|
||||
- description: Corner 1 quotient offset
|
||||
- description: Corner 2 quotient offset
|
||||
- description: Corner 3 quotient offset
|
||||
- description: Corner 1 initial voltage
|
||||
- description: Corner 2 initial voltage
|
||||
- description: Corner 3 initial voltage
|
||||
- description: Corner 1 quotient
|
||||
- description: Corner 2 quotient
|
||||
- description: Corner 3 quotient
|
||||
- description: Corner 1 ring oscillator
|
||||
- description: Corner 2 ring oscillator
|
||||
- description: Corner 3 ring oscillator
|
||||
- description: Fuse revision
|
||||
|
||||
nvmem-cell-names:
|
||||
items:
|
||||
- const: cpr_quotient_offset1
|
||||
- const: cpr_quotient_offset2
|
||||
- const: cpr_quotient_offset3
|
||||
- const: cpr_init_voltage1
|
||||
- const: cpr_init_voltage2
|
||||
- const: cpr_init_voltage3
|
||||
- const: cpr_quotient1
|
||||
- const: cpr_quotient2
|
||||
- const: cpr_quotient3
|
||||
- const: cpr_ring_osc1
|
||||
- const: cpr_ring_osc2
|
||||
- const: cpr_ring_osc3
|
||||
- const: cpr_fuse_revision
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- vdd-apc-supply
|
||||
- '#power-domain-cells'
|
||||
- operating-points-v2
|
||||
- nvmem-cells
|
||||
- nvmem-cell-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
cpr_opp_table: opp-table-cpr {
|
||||
compatible = "operating-points-v2-qcom-level";
|
||||
|
||||
cpr_opp1: opp1 {
|
||||
opp-level = <1>;
|
||||
qcom,opp-fuse-level = <1>;
|
||||
};
|
||||
cpr_opp2: opp2 {
|
||||
opp-level = <2>;
|
||||
qcom,opp-fuse-level = <2>;
|
||||
};
|
||||
cpr_opp3: opp3 {
|
||||
opp-level = <3>;
|
||||
qcom,opp-fuse-level = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
power-controller@b018000 {
|
||||
compatible = "qcom,qcs404-cpr", "qcom,cpr";
|
||||
reg = <0x0b018000 0x1000>;
|
||||
interrupts = <0 15 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&xo_board>;
|
||||
clock-names = "ref";
|
||||
vdd-apc-supply = <&pms405_s3>;
|
||||
#power-domain-cells = <0>;
|
||||
operating-points-v2 = <&cpr_opp_table>;
|
||||
acc-syscon = <&tcsr>;
|
||||
|
||||
nvmem-cells = <&cpr_efuse_quot_offset1>,
|
||||
<&cpr_efuse_quot_offset2>,
|
||||
<&cpr_efuse_quot_offset3>,
|
||||
<&cpr_efuse_init_voltage1>,
|
||||
<&cpr_efuse_init_voltage2>,
|
||||
<&cpr_efuse_init_voltage3>,
|
||||
<&cpr_efuse_quot1>,
|
||||
<&cpr_efuse_quot2>,
|
||||
<&cpr_efuse_quot3>,
|
||||
<&cpr_efuse_ring1>,
|
||||
<&cpr_efuse_ring2>,
|
||||
<&cpr_efuse_ring3>,
|
||||
<&cpr_efuse_revision>;
|
||||
nvmem-cell-names = "cpr_quotient_offset1",
|
||||
"cpr_quotient_offset2",
|
||||
"cpr_quotient_offset3",
|
||||
"cpr_init_voltage1",
|
||||
"cpr_init_voltage2",
|
||||
"cpr_init_voltage3",
|
||||
"cpr_quotient1",
|
||||
"cpr_quotient2",
|
||||
"cpr_quotient3",
|
||||
"cpr_ring_osc1",
|
||||
"cpr_ring_osc2",
|
||||
"cpr_ring_osc3",
|
||||
"cpr_fuse_revision";
|
||||
};
|
|
@ -113,6 +113,16 @@ to: return warning/error, stop working or panic.
|
|||
See Section 3. for an example of driver implementing this
|
||||
callback, or Section 2.4 for further documentation on this API
|
||||
|
||||
Registration of EM using DT
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The EM can also be registered using OPP framework and information in DT
|
||||
"operating-points-v2". Each OPP entry in DT can be extended with a property
|
||||
"opp-microwatt" containing micro-Watts power value. This OPP DT property
|
||||
allows a platform to register EM power values which are reflecting total power
|
||||
(static + dynamic). These power values might be coming directly from
|
||||
experiments and measurements.
|
||||
|
||||
Registration of 'simple' EM
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -10079,6 +10079,7 @@ INTEL UNCORE FREQUENCY CONTROL
|
|||
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst
|
||||
F: drivers/platform/x86/intel/uncore-frequency/
|
||||
|
||||
INTEL VENDOR SPECIFIC EXTENDED CAPABILITIES DRIVER
|
||||
|
@ -16249,14 +16250,15 @@ M: Niklas Cassel <nks@flawful.org>
|
|||
L: linux-pm@vger.kernel.org
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
|
||||
F: Documentation/devicetree/bindings/power/avs/qcom,cpr.yaml
|
||||
F: drivers/soc/qcom/cpr.c
|
||||
|
||||
QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096
|
||||
M: Ilia Lin <ilia.lin@kernel.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
|
||||
F: Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-nvmem.yaml
|
||||
F: Documentation/devicetree/bindings/opp/opp-v2-kryo-cpu.yaml
|
||||
F: drivers/cpufreq/qcom-cpufreq-nvmem.c
|
||||
|
||||
QUALCOMM CRYPTO DRIVERS
|
||||
|
|
|
@ -76,6 +76,22 @@
|
|||
clock-latency = <61036>; /* two CLK32 periods */
|
||||
clocks = <&clks IMX7D_CLK_ARM>;
|
||||
cpu-idle-states = <&cpu_sleep_wait>;
|
||||
operating-points-v2 = <&cpu0_opp_table>;
|
||||
#cooling-cells = <2>;
|
||||
nvmem-cells = <&fuse_grade>;
|
||||
nvmem-cell-names = "speed_grade";
|
||||
};
|
||||
};
|
||||
|
||||
cpu0_opp_table: opp-table {
|
||||
compatible = "operating-points-v2";
|
||||
opp-shared;
|
||||
|
||||
opp-792000000 {
|
||||
opp-hz = /bits/ 64 <792000000>;
|
||||
opp-microvolt = <1000000>;
|
||||
clock-latency-ns = <150000>;
|
||||
opp-supported-hw = <0xf>, <0xf>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -303,52 +303,48 @@ static u64 cppc_get_dmi_max_khz(void)
|
|||
|
||||
/*
|
||||
* If CPPC lowest_freq and nominal_freq registers are exposed then we can
|
||||
* use them to convert perf to freq and vice versa
|
||||
*
|
||||
* If the perf/freq point lies between Nominal and Lowest, we can treat
|
||||
* (Low perf, Low freq) and (Nom Perf, Nom freq) as 2D co-ordinates of a line
|
||||
* and extrapolate the rest
|
||||
* For perf/freq > Nominal, we use the ratio perf:freq at Nominal for conversion
|
||||
* use them to convert perf to freq and vice versa. The conversion is
|
||||
* extrapolated as an affine function passing by the 2 points:
|
||||
* - (Low perf, Low freq)
|
||||
* - (Nominal perf, Nominal perf)
|
||||
*/
|
||||
static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu_data,
|
||||
unsigned int perf)
|
||||
{
|
||||
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
|
||||
s64 retval, offset = 0;
|
||||
static u64 max_khz;
|
||||
u64 mul, div;
|
||||
|
||||
if (caps->lowest_freq && caps->nominal_freq) {
|
||||
if (perf >= caps->nominal_perf) {
|
||||
mul = caps->nominal_freq;
|
||||
div = caps->nominal_perf;
|
||||
} else {
|
||||
mul = caps->nominal_freq - caps->lowest_freq;
|
||||
div = caps->nominal_perf - caps->lowest_perf;
|
||||
}
|
||||
mul = caps->nominal_freq - caps->lowest_freq;
|
||||
div = caps->nominal_perf - caps->lowest_perf;
|
||||
offset = caps->nominal_freq - div64_u64(caps->nominal_perf * mul, div);
|
||||
} else {
|
||||
if (!max_khz)
|
||||
max_khz = cppc_get_dmi_max_khz();
|
||||
mul = max_khz;
|
||||
div = caps->highest_perf;
|
||||
}
|
||||
return (u64)perf * mul / div;
|
||||
|
||||
retval = offset + div64_u64(perf * mul, div);
|
||||
if (retval >= 0)
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu_data,
|
||||
unsigned int freq)
|
||||
{
|
||||
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
|
||||
s64 retval, offset = 0;
|
||||
static u64 max_khz;
|
||||
u64 mul, div;
|
||||
|
||||
if (caps->lowest_freq && caps->nominal_freq) {
|
||||
if (freq >= caps->nominal_freq) {
|
||||
mul = caps->nominal_perf;
|
||||
div = caps->nominal_freq;
|
||||
} else {
|
||||
mul = caps->lowest_perf;
|
||||
div = caps->lowest_freq;
|
||||
}
|
||||
mul = caps->nominal_perf - caps->lowest_perf;
|
||||
div = caps->nominal_freq - caps->lowest_freq;
|
||||
offset = caps->nominal_perf - div64_u64(caps->nominal_freq * mul, div);
|
||||
} else {
|
||||
if (!max_khz)
|
||||
max_khz = cppc_get_dmi_max_khz();
|
||||
|
@ -356,7 +352,10 @@ static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu_data,
|
|||
div = max_khz;
|
||||
}
|
||||
|
||||
return (u64)freq * mul / div;
|
||||
retval = offset + div64_u64(freq * mul, div);
|
||||
if (retval >= 0)
|
||||
return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
|
||||
|
|
|
@ -110,6 +110,7 @@ static const struct of_device_id blocklist[] __initconst = {
|
|||
|
||||
{ .compatible = "fsl,imx7ulp", },
|
||||
{ .compatible = "fsl,imx7d", },
|
||||
{ .compatible = "fsl,imx7s", },
|
||||
{ .compatible = "fsl,imx8mq", },
|
||||
{ .compatible = "fsl,imx8mm", },
|
||||
{ .compatible = "fsl,imx8mn", },
|
||||
|
@ -138,9 +139,11 @@ static const struct of_device_id blocklist[] __initconst = {
|
|||
{ .compatible = "qcom,msm8996", },
|
||||
{ .compatible = "qcom,qcs404", },
|
||||
{ .compatible = "qcom,sa8155p" },
|
||||
{ .compatible = "qcom,sa8540p" },
|
||||
{ .compatible = "qcom,sc7180", },
|
||||
{ .compatible = "qcom,sc7280", },
|
||||
{ .compatible = "qcom,sc8180x", },
|
||||
{ .compatible = "qcom,sc8280xp", },
|
||||
{ .compatible = "qcom,sdm845", },
|
||||
{ .compatible = "qcom,sm6350", },
|
||||
{ .compatible = "qcom,sm8150", },
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
struct qcom_cpufreq_soc_data {
|
||||
u32 reg_enable;
|
||||
u32 reg_dcvs_ctrl;
|
||||
u32 reg_freq_lut;
|
||||
u32 reg_volt_lut;
|
||||
u32 reg_current_vote;
|
||||
|
@ -50,6 +51,8 @@ struct qcom_cpufreq_data {
|
|||
bool cancel_throttle;
|
||||
struct delayed_work throttle_work;
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
bool per_core_dcvs;
|
||||
};
|
||||
|
||||
static unsigned long cpu_hw_rate, xo_rate;
|
||||
|
@ -102,9 +105,14 @@ static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy,
|
|||
struct qcom_cpufreq_data *data = policy->driver_data;
|
||||
const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
|
||||
unsigned long freq = policy->freq_table[index].frequency;
|
||||
unsigned int i;
|
||||
|
||||
writel_relaxed(index, data->base + soc_data->reg_perf_state);
|
||||
|
||||
if (data->per_core_dcvs)
|
||||
for (i = 1; i < cpumask_weight(policy->related_cpus); i++)
|
||||
writel_relaxed(index, data->base + soc_data->reg_perf_state + i * 4);
|
||||
|
||||
if (icc_scaling_enabled)
|
||||
qcom_cpufreq_set_bw(policy, freq);
|
||||
|
||||
|
@ -137,10 +145,15 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
|
|||
struct qcom_cpufreq_data *data = policy->driver_data;
|
||||
const struct qcom_cpufreq_soc_data *soc_data = data->soc_data;
|
||||
unsigned int index;
|
||||
unsigned int i;
|
||||
|
||||
index = policy->cached_resolved_idx;
|
||||
writel_relaxed(index, data->base + soc_data->reg_perf_state);
|
||||
|
||||
if (data->per_core_dcvs)
|
||||
for (i = 1; i < cpumask_weight(policy->related_cpus); i++)
|
||||
writel_relaxed(index, data->base + soc_data->reg_perf_state + i * 4);
|
||||
|
||||
return policy->freq_table[index].frequency;
|
||||
}
|
||||
|
||||
|
@ -342,6 +355,7 @@ static irqreturn_t qcom_lmh_dcvs_handle_irq(int irq, void *data)
|
|||
|
||||
static const struct qcom_cpufreq_soc_data qcom_soc_data = {
|
||||
.reg_enable = 0x0,
|
||||
.reg_dcvs_ctrl = 0xbc,
|
||||
.reg_freq_lut = 0x110,
|
||||
.reg_volt_lut = 0x114,
|
||||
.reg_current_vote = 0x704,
|
||||
|
@ -351,6 +365,7 @@ static const struct qcom_cpufreq_soc_data qcom_soc_data = {
|
|||
|
||||
static const struct qcom_cpufreq_soc_data epss_soc_data = {
|
||||
.reg_enable = 0x0,
|
||||
.reg_dcvs_ctrl = 0xb0,
|
||||
.reg_freq_lut = 0x100,
|
||||
.reg_volt_lut = 0x200,
|
||||
.reg_perf_state = 0x320,
|
||||
|
@ -481,8 +496,11 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (readl_relaxed(base + data->soc_data->reg_dcvs_ctrl) & 0x1)
|
||||
data->per_core_dcvs = true;
|
||||
|
||||
qcom_get_related_cpus(index, policy->cpus);
|
||||
if (!cpumask_weight(policy->cpus)) {
|
||||
if (cpumask_empty(policy->cpus)) {
|
||||
dev_err(dev, "Domain-%d failed to get related CPUs\n", index);
|
||||
ret = -ENOENT;
|
||||
goto error;
|
||||
|
|
|
@ -130,7 +130,7 @@ static void get_krait_bin_format_b(struct device *cpu_dev,
|
|||
}
|
||||
|
||||
/* Check PVS_BLOW_STATUS */
|
||||
pte_efuse = *(((u32 *)buf) + 4);
|
||||
pte_efuse = *(((u32 *)buf) + 1);
|
||||
pte_efuse &= BIT(21);
|
||||
if (pte_efuse) {
|
||||
dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
|
||||
|
|
|
@ -154,7 +154,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
|
|||
* table and opp-shared.
|
||||
*/
|
||||
ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, priv->opp_shared_cpus);
|
||||
if (ret || !cpumask_weight(priv->opp_shared_cpus)) {
|
||||
if (ret || cpumask_empty(priv->opp_shared_cpus)) {
|
||||
/*
|
||||
* Either opp-table is not set or no opp-shared was found.
|
||||
* Use the CPU mask from SCMI to designate CPUs sharing an OPP
|
||||
|
|
|
@ -113,6 +113,31 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_get_power() - Gets the power corresponding to an opp
|
||||
* @opp: opp for which power has to be returned for
|
||||
*
|
||||
* Return: power in micro watt corresponding to the opp, else
|
||||
* return 0
|
||||
*
|
||||
* This is useful only for devices with single power supply.
|
||||
*/
|
||||
unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp)
|
||||
{
|
||||
unsigned long opp_power = 0;
|
||||
int i;
|
||||
|
||||
if (IS_ERR_OR_NULL(opp)) {
|
||||
pr_err("%s: Invalid parameters\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < opp->opp_table->regulator_count; i++)
|
||||
opp_power += opp->supplies[i].u_watt;
|
||||
|
||||
return opp_power;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_get_power);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp
|
||||
* @opp: opp for which frequency has to be returned for
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -99,6 +100,9 @@ static void opp_debug_create_supplies(struct dev_pm_opp *opp,
|
|||
|
||||
debugfs_create_ulong("u_amp", S_IRUGO, d,
|
||||
&opp->supplies[i].u_amp);
|
||||
|
||||
debugfs_create_ulong("u_watt", S_IRUGO, d,
|
||||
&opp->supplies[i].u_watt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,9 +135,13 @@ void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
|
|||
debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend);
|
||||
debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate);
|
||||
debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate);
|
||||
debugfs_create_u32("level", S_IRUGO, d, &opp->level);
|
||||
debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
|
||||
&opp->clock_latency_ns);
|
||||
|
||||
opp->of_name = of_node_full_name(opp->np);
|
||||
debugfs_create_str("of_name", S_IRUGO, d, (char **)&opp->of_name);
|
||||
|
||||
opp_debug_create_supplies(opp, opp_table, d);
|
||||
opp_debug_create_bw(opp, opp_table, d);
|
||||
|
||||
|
|
108
drivers/opp/of.c
108
drivers/opp/of.c
|
@ -575,8 +575,9 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
|
|||
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
|
||||
struct opp_table *opp_table)
|
||||
{
|
||||
u32 *microvolt, *microamp = NULL;
|
||||
int supplies = opp_table->regulator_count, vcount, icount, ret, i, j;
|
||||
u32 *microvolt, *microamp = NULL, *microwatt = NULL;
|
||||
int supplies = opp_table->regulator_count;
|
||||
int vcount, icount, pcount, ret, i, j;
|
||||
struct property *prop = NULL;
|
||||
char name[NAME_MAX];
|
||||
|
||||
|
@ -688,6 +689,43 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
/* Search for "opp-microwatt" */
|
||||
sprintf(name, "opp-microwatt");
|
||||
prop = of_find_property(opp->np, name, NULL);
|
||||
|
||||
if (prop) {
|
||||
pcount = of_property_count_u32_elems(opp->np, name);
|
||||
if (pcount < 0) {
|
||||
dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
|
||||
name, pcount);
|
||||
ret = pcount;
|
||||
goto free_microamp;
|
||||
}
|
||||
|
||||
if (pcount != supplies) {
|
||||
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
|
||||
__func__, name, pcount, supplies);
|
||||
ret = -EINVAL;
|
||||
goto free_microamp;
|
||||
}
|
||||
|
||||
microwatt = kmalloc_array(pcount, sizeof(*microwatt),
|
||||
GFP_KERNEL);
|
||||
if (!microwatt) {
|
||||
ret = -EINVAL;
|
||||
goto free_microamp;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(opp->np, name, microwatt,
|
||||
pcount);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: error parsing %s: %d\n", __func__,
|
||||
name, ret);
|
||||
ret = -EINVAL;
|
||||
goto free_microwatt;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < supplies; i++) {
|
||||
opp->supplies[i].u_volt = microvolt[j++];
|
||||
|
||||
|
@ -701,8 +739,13 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
|
|||
|
||||
if (microamp)
|
||||
opp->supplies[i].u_amp = microamp[i];
|
||||
|
||||
if (microwatt)
|
||||
opp->supplies[i].u_watt = microwatt[i];
|
||||
}
|
||||
|
||||
free_microwatt:
|
||||
kfree(microwatt);
|
||||
free_microamp:
|
||||
kfree(microamp);
|
||||
free_microvolt:
|
||||
|
@ -1395,6 +1438,38 @@ struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
|
||||
|
||||
/*
|
||||
* Callback function provided to the Energy Model framework upon registration.
|
||||
* It provides the power used by @dev at @kHz if it is the frequency of an
|
||||
* existing OPP, or at the frequency of the first OPP above @kHz otherwise
|
||||
* (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
|
||||
* frequency and @mW to the associated power.
|
||||
*
|
||||
* Returns 0 on success or a proper -EINVAL value in case of error.
|
||||
*/
|
||||
static int __maybe_unused
|
||||
_get_dt_power(unsigned long *mW, unsigned long *kHz, struct device *dev)
|
||||
{
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long opp_freq, opp_power;
|
||||
|
||||
/* Find the right frequency and related OPP */
|
||||
opp_freq = *kHz * 1000;
|
||||
opp = dev_pm_opp_find_freq_ceil(dev, &opp_freq);
|
||||
if (IS_ERR(opp))
|
||||
return -EINVAL;
|
||||
|
||||
opp_power = dev_pm_opp_get_power(opp);
|
||||
dev_pm_opp_put(opp);
|
||||
if (!opp_power)
|
||||
return -EINVAL;
|
||||
|
||||
*kHz = opp_freq / 1000;
|
||||
*mW = opp_power / 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function provided to the Energy Model framework upon registration.
|
||||
* This computes the power estimated by @dev at @kHz if it is the frequency
|
||||
|
@ -1445,6 +1520,24 @@ static int __maybe_unused _get_power(unsigned long *mW, unsigned long *kHz,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool _of_has_opp_microwatt_property(struct device *dev)
|
||||
{
|
||||
unsigned long power, freq = 0;
|
||||
struct dev_pm_opp *opp;
|
||||
|
||||
/* Check if at least one OPP has needed property */
|
||||
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
||||
if (IS_ERR(opp))
|
||||
return false;
|
||||
|
||||
power = dev_pm_opp_get_power(opp);
|
||||
dev_pm_opp_put(opp);
|
||||
if (!power)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_pm_opp_of_register_em() - Attempt to register an Energy Model
|
||||
* @dev : Device for which an Energy Model has to be registered
|
||||
|
@ -1458,7 +1551,7 @@ static int __maybe_unused _get_power(unsigned long *mW, unsigned long *kHz,
|
|||
*/
|
||||
int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
|
||||
{
|
||||
struct em_data_callback em_cb = EM_DATA_CB(_get_power);
|
||||
struct em_data_callback em_cb;
|
||||
struct device_node *np;
|
||||
int ret, nr_opp;
|
||||
u32 cap;
|
||||
|
@ -1474,6 +1567,12 @@ int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
|
|||
goto failed;
|
||||
}
|
||||
|
||||
/* First, try to find more precised Energy Model in DT */
|
||||
if (_of_has_opp_microwatt_property(dev)) {
|
||||
EM_SET_ACTIVE_POWER_CB(em_cb, _get_dt_power);
|
||||
goto register_em;
|
||||
}
|
||||
|
||||
np = of_node_get(dev->of_node);
|
||||
if (!np) {
|
||||
ret = -EINVAL;
|
||||
|
@ -1495,6 +1594,9 @@ int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
|
|||
goto failed;
|
||||
}
|
||||
|
||||
EM_SET_ACTIVE_POWER_CB(em_cb, _get_power);
|
||||
|
||||
register_em:
|
||||
ret = em_dev_register_perf_domain(dev, nr_opp, &em_cb, cpus, true);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
|
|
@ -96,6 +96,7 @@ struct dev_pm_opp {
|
|||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *dentry;
|
||||
const char *of_name;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -116,6 +116,7 @@ struct em_data_callback {
|
|||
struct device *dev);
|
||||
};
|
||||
#define EM_DATA_CB(_active_power_cb) { .active_power = &_active_power_cb }
|
||||
#define EM_SET_ACTIVE_POWER_CB(em_cb, cb) ((em_cb).active_power = cb)
|
||||
|
||||
struct em_perf_domain *em_cpu_get(int cpu);
|
||||
struct em_perf_domain *em_pd_get(struct device *dev);
|
||||
|
@ -264,6 +265,7 @@ static inline int em_pd_nr_perf_states(struct em_perf_domain *pd)
|
|||
#else
|
||||
struct em_data_callback {};
|
||||
#define EM_DATA_CB(_active_power_cb) { }
|
||||
#define EM_SET_ACTIVE_POWER_CB(em_cb, cb) do { } while (0)
|
||||
|
||||
static inline
|
||||
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
|
||||
|
|
|
@ -32,14 +32,17 @@ enum dev_pm_opp_event {
|
|||
* @u_volt_min: Minimum voltage in microvolts corresponding to this OPP
|
||||
* @u_volt_max: Maximum voltage in microvolts corresponding to this OPP
|
||||
* @u_amp: Maximum current drawn by the device in microamperes
|
||||
* @u_watt: Power used by the device in microwatts
|
||||
*
|
||||
* This structure stores the voltage/current values for a single power supply.
|
||||
* This structure stores the voltage/current/power values for a single power
|
||||
* supply.
|
||||
*/
|
||||
struct dev_pm_opp_supply {
|
||||
unsigned long u_volt;
|
||||
unsigned long u_volt_min;
|
||||
unsigned long u_volt_max;
|
||||
unsigned long u_amp;
|
||||
unsigned long u_watt;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -94,6 +97,8 @@ void dev_pm_opp_put_opp_table(struct opp_table *opp_table);
|
|||
|
||||
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
|
||||
|
||||
unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp);
|
||||
|
||||
unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
|
||||
|
||||
unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp);
|
||||
|
@ -186,6 +191,11 @@ static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long dev_pm_opp_get_power(struct dev_pm_opp *opp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
|
||||
{
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue