cpufreq: qcom-hw: Add support for QCOM cpufreq HW
v13 cover cpufreq: qcom-hw: Add support for QCOM cpufreq HW
[v13]
* Update Documentation binding to #freq-domain-cells in description.
* Replace devm_ioremap_resource() to use devm_ioremap() API.
[v12]
* Remove per-cpu domain global structure.
[v11]
* Updated the code logic as per Stephen.
* Default boost enabled is removed.
* Update the clock name to use "alternate" for GPLL0 source in code and Documentation binding.
* Module description updated.
* perf_base updated to perf_state_reg.
[v10]
* Update Documentation binding for cpufreq node.
* Make the driver 'tristate' instead of 'bool' and update code.
* Update the clock name to reflect the hardware name.
* Remove support for varying offset.
[v9]
* Update the Documentation binding for freq-domain-cells & cpufreq node.
* Address comments in Kconfig.arm & Makefile.
* Remove include file & MODULE_DESCRIPTION not required.
* Fix the code for 'of_node_put(cpu_np)'.
[v8]
* Address comments to update code to take cpufreq_hw phandle and index from the CPU nodes.
* Updated the Documentation for the above change in DT.
* Updated logic for assigning 'qcom_freq_domain_map' for related CPUs.
* Clock input to the HW block is taken from DT which has been updated in code and Device tree documentation.
[v7]
* Updated the logic to check for related CPUs.
[v6]
* Renamed match table 'qcom_cpufreq_hw_match'.
* Renamed 'qcom_read_lut' to 'qcom_cpufreq_hw_read_lut'.
* Updated the logic to check for related CPUs at the beginning of the 'qcom_cpu_resources_init'.
* Use devm_ioremap_resource instead of devm_ioremap.
* Update the use of of_node_put to handle error conditions.
* Use policy->cached_resolved_idx in fast switch callback.
* Keep precalculated offsets 'reg_bases'.
* XO clock is taken from Device tree.
* Update documentation binding for clocks/clock-names.
* Minor comments in Kconfig.arm.
* Comments to move dev_info to dev_dbg.
[v5]
* Remove mapping different register regions of perf/lut/enable, instead map the entire HW region.
* Add reg_offset/cpufreq_qcom_std_offsets to be supplied as device data.
* Check of src == 0 during lut read.
* Add of_node_put(cpu_np) in qcom_get_related_cpus
* Update the qcom_cpu_resources_init for register offset data, and cleanup the related cpus to keep a single copy of CPUfreq.
* Replace FW with HW, update Kconfig, rename filename qcom-cpufreq-hw.c
* Update the documentation binding to reflect the changes of mapping the
* entire HW region.
[v4]
* Fixed console messages as per comments.
* Return error from qcom_resources_init()
in the cases where failed to get frequency domain.
* Rename cpu_dev to cpu_np in qcom_resources_init, qcom_get_related_cpus(). Also use temp variable freq_np in qcom_get_related_cpus().
* Update qcom_cpufreq_fw_get() to use the policy data to incoporate the hotplug use case.
* Update code to use of fast_switching.
* Check for !c->max_cores instead of cpumask_empty in qcom_get_related_cpus().
* Update the logic of assigning 'c' to qcom_freq_domain_map[cpu].
[v3]
* Remove index check from 'qcom_cpufreq_fw_target_index'.
* Update the Documentation binding to add the platform specific properties in the CPU nodes, node name "qcom,freq-domain".
* Update return value to '0' from -ENODEV from 'qcom_cpufreq_fw_get'.
* Update the logic for boost frequency to use local variables instead of cpufreq driver data in 'qcom_read_lut'.
* Update the logic in 'qcom_get_related_cpus' to find the related cpus.
* Update the reg-names to remove "_base" and also update the binding with the description of these registers.
* Update the logic in 'qcom_resources_init' to address the new device tree notation of handling the frequency domain phandles.
[v2]
* Fixed the alignment issues in "qcom_cpufreq_fw_target_index" for dev_err and also for "qcom_cpu_resources_init".
* Removed ret = 0 from qcom_get_related_cpus and added to check for cpu_mask_empty to return -ENOENT.
* Fixes qcom_cpu_resources_init function
* Remove initialization of 'index'
* Check for valid 'c'
* Removed initialization of 'prev_cc' from 'qcom_read_lut'.
Taniya Das (2):
dt-bindings: cpufreq: Introduce QCOM CPUFREQ Firmware bindings
cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
.../bindings/cpufreq/cpufreq-qcom-hw.txt | 172 ++++++++++++ drivers/cpufreq/Kconfig.arm | 11 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 308 +++++++++++++++++++++ 4 files changed, 492 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt create mode 100644 drivers/cpufreq/qcom-cpufreq-hw.c
--
Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
PATCH v13 1/2 dt-bindings: cpufreq: Introduce QCOM CPUFREQ Firmware bindings
Add QCOM cpufreq firmware device bindings for Qualcomm Technology Inc's SoCs. This is required for managing the cpu frequency transitions which are controlled by the hardware engine.
--- .../bindings/cpufreq/cpufreq-qcom-hw.txt | 172 +++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file +172 -0
@@ -0,0 +1,172 @@ +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". + +- 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>; + }; +}
--
Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Re: [PATCH v13 1/2] dt-bindings: cpufreq: Introduce QCOM CPUFREQ Firmware bindings
Quoting Taniya Das (2018-12-13 20:10:23)
Quoted 6 lines
Add QCOM cpufreq firmware device bindings for Qualcomm Technology Inc's SoCs. This is required for managing the cpu frequency transitions which are controlled by the hardware engine.
Signed-off-by Taniya Das <[email protected]>---
except one question below for Rob.
Quoted 30 lines
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file +24
-0@@ -0,0 +1,172 @@ +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". + +- 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
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt line 34
Quoted 10 lines
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file +10
-0+ 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:
I still wonder if this should be #qcom,freq-domain-cells, but if Rob is OK I won't complain.
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt line 35
Quoted 1 line
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file +1
-0+ Usage: required.
Nitpick: Weird full-stop here ^
Quoted 7 lines
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file +7
-0+ 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. + +
Rob Herring
maintainerRe: [PATCH v13 1/2] dt-bindings: cpufreq: Introduce QCOM CPUFREQ Firmware bindings
Quoted 47 lines · Stephen Boyd
Quoting Taniya Das (2018-12-13 20:10:23)
Quoted 6 lines
Add QCOM cpufreq firmware device bindings for Qualcomm Technology Inc's SoCs. This is required for managing the cpu frequency transitions which are controlled by the hardware engine.
Signed-off-by Taniya Das <[email protected]>---
Reviewed-by Stephen Boyd <[email protected]>except one question below for Rob.
Quoted 35 lines
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file +29
-0@@ -0,0 +1,172 @@ +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". + +- 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
Quoted 8 lines
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt line 34
Quoted 5 lines
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file +5
-0+ Value type: <string> + Definition: Frequency domain name i.e. + "freq-domain0", "freq-domain1". + +- #freq-domain-cells:I still wonder if this should be #qcom,freq-domain-cells, but if Rob is OK I won't complain.
Probably should be. Though I did give my R-by without.
Rob
Re: [PATCH v13 1/2] dt-bindings: cpufreq: Introduce QCOM CPUFREQ Firmware bindings
In reply to Taniya DasQuoted 6 lines · Taniya Das
Add QCOM cpufreq firmware device bindings for Qualcomm Technology Inc's SoCs. This is required for managing the cpu frequency transitions which are controlled by the hardware engine.
Signed-off-by Taniya Das <[email protected]>
Quoted 187 lines
--- .../bindings/cpufreq/cpufreq-qcom-hw.txt | 172 +++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txtDocumentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file +172
-1@@ -0,0 +1,172 @@ +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". + +- 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>; + }; +} --Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Re: [PATCH v13 1/2] dt-bindings: cpufreq: Introduce QCOM CPUFREQ Firmware bindings
In reply to Taniya DasQuoted 10 lines · Taniya Das
Add QCOM cpufreq firmware device bindings for Qualcomm Technology Inc's SoCs. This is required for managing the cpu frequency transitions which are controlled by the hardware engine.
Signed-off-by Taniya Das <[email protected]>--- .../bindings/cpufreq/cpufreq-qcom-hw.txt | 172 +++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt
PATCH v13 2/2 cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
In reply to Taniya DasThe CPUfreq HW present in some QCOM chipsets offloads the steps necessary for changing the frequency of CPUs. The driver implements the cpufreq driver interface for this hardware engine.
--- drivers/cpufreq/Kconfig.arm | 11 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 308 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 320 insertions(+) create mode 100644 drivers/cpufreq/qcom-cpufreq-hw.c
drivers/cpufreq/Kconfig.arm +11 -0
@@ -114,6 +114,17 @@ config ARM_QCOM_CPUFREQ_KRYO If in doubt, say N. +config ARM_QCOM_CPUFREQ_HW + tristate "QCOM CPUFreq HW driver" + depends on ARCH_QCOM || COMPILE_TEST + help + Support for the CPUFreq HW driver. + Some QCOM chipsets have a HW engine to offload the steps + necessary for changing the frequency of the CPUs. Firmware loaded + in this engine exposes a programming interface to the OS. + The driver implements the cpufreq interface for this HW engine. + Say Y if you want to support CPUFreq HW. + config ARM_S3C_CPUFREQ bool help
drivers/cpufreq/Makefile +1 -0
@@ -61,6 +61,7 @@ obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
drivers/cpufreq/qcom-cpufreq-hw.c new file +308 -0
308 lines not on this page · raw message
--
Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Re: [PATCH v13 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
Quoting Taniya Das (2018-12-13 20:10:24)
Quoted 8 lines
The CPUfreq HW present in some QCOM chipsets offloads the steps necessary for changing the frequency of CPUs. The driver implements the cpufreq driver interface for this hardware engine.
Signed-off-by Saravana Kannan <[email protected]>Signed-off-by Stephen Boyd <[email protected]>Signed-off-by Taniya Das <[email protected]>---
Re: [PATCH v13 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
In reply to Taniya DasQuoted 7 lines · Taniya Das
The CPUfreq HW present in some QCOM chipsets offloads the steps necessary for changing the frequency of CPUs. The driver implements the cpufreq driver interface for this hardware engine.
Signed-off-by Saravana Kannan <[email protected]>Signed-off-by Stephen Boyd <[email protected]>Signed-off-by Taniya Das <[email protected]>
I think it's common practice to carry over tags like 'Reviewed-by' or 'Acked-by' for trivial changes.
Quoted 345 lines
--- drivers/cpufreq/Kconfig.arm | 11 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 308 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 320 insertions(+) create mode 100644 drivers/cpufreq/qcom-cpufreq-hw.cdrivers/cpufreq/Kconfig.arm +11
-0@@ -114,6 +114,17 @@ config ARM_QCOM_CPUFREQ_KRYO If in doubt, say N. +config ARM_QCOM_CPUFREQ_HW + tristate "QCOM CPUFreq HW driver" + depends on ARCH_QCOM || COMPILE_TEST + help + Support for the CPUFreq HW driver. + Some QCOM chipsets have a HW engine to offload the steps + necessary for changing the frequency of the CPUs. Firmware loaded + in this engine exposes a programming interface to the OS. + The driver implements the cpufreq interface for this HW engine. + Say Y if you want to support CPUFreq HW. + config ARM_S3C_CPUFREQ bool helpdrivers/cpufreq/Makefile +1
-0@@ -61,6 +61,7 @@ obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.odrivers/cpufreq/qcom-cpufreq-hw.c new file +298
-0@@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2018, The Linux Foundation. All rights reserved. +*/ + +#include <linux/bitfield.h> +#include <linux/cpufreq.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/slab.h> + +#define LUT_MAX_ENTRIES 40U +#define LUT_SRC GENMASK(31, 30) +#define LUT_L_VAL GENMASK(7, 0) +#define LUT_CORE_COUNT GENMASK(18, 16) +#define LUT_ROW_SIZE 32 +#define CLK_HW_DIV 2 + +/* Register offsets */ +#define REG_ENABLE 0x0 +#define REG_LUT_TABLE 0x110 +#define REG_PERF_STATE 0x920 + +static unsigned long cpu_hw_rate, xo_rate; +static struct platform_device *global_pdev; + +static int qcom_cpufreq_hw_target_index (struct cpufreq_policy *policy, +unsigned int index) +{ +void __iomem *perf_state_reg = policy->driver_data; + +writel_relaxed (index, perf_state_reg); + +return 0 ; +} + +static unsigned int qcom_cpufreq_hw_get (unsigned int cpu) +{ +void __iomem *perf_state_reg; +struct cpufreq_policy *policy; +unsigned int index; + + policy =cpufreq_cpu_get_raw (cpu); +if (!policy) +return 0 ; + + perf_state_reg = policy->driver_data; + + index =readl_relaxed (perf_state_reg); + index =min (index,LUT_MAX_ENTRIES -1 ); + +return policy->freq_table[index].frequency; +} + +static unsigned int qcom_cpufreq_hw_fast_switch (struct cpufreq_policy *policy, +unsigned int target_freq) +{ +void __iomem *perf_state_reg = policy->driver_data; +int index; + + index = policy->cached_resolved_idx; +if (index <0 ) +return 0 ; + +writel_relaxed (index, perf_state_reg); + +return policy->freq_table[index].frequency; +} + +static int qcom_cpufreq_hw_read_lut (struct device *dev, +struct cpufreq_policy *policy, +void __iomem *base) +{ +u32 data, src, lval, i, core_count, prev_cc =0 , prev_freq =0 , freq; +unsigned int max_cores =cpumask_weight (policy->cpus); +struct cpufreq_frequency_table *table; + + table =kcalloc (LUT_MAX_ENTRIES +1 ,sizeof (*table),GFP_KERNEL ); +if (!table) +return -ENOMEM ; + +for (i =0 ; i <LUT_MAX_ENTRIES ; i++) { + data =readl_relaxed (base +REG_LUT_TABLE + i *LUT_ROW_SIZE ); + src =FIELD_GET (LUT_SRC , data); + lval =FIELD_GET (LUT_L_VAL , data); + core_count =FIELD_GET (LUT_CORE_COUNT , data); + +if (src) + freq = xo_rate * lval /1000 ; +else + freq = cpu_hw_rate /1000 ; + +/* Ignore boosts in the middle of the table */ +if (core_count != max_cores) { + table[i].frequency =CPUFREQ_ENTRY_INVALID ; + }else { + table[i].frequency = freq; +dev_dbg (dev,"index=%d freq=%d, core_count %d\n" , i, + freq, core_count); + } + +/* +* Two of the same frequencies with the same core counts means +* end of table +*/ +if (i >0 && prev_freq == freq && prev_cc == core_count) { +struct cpufreq_frequency_table *prev = &table[i -1 ]; + +/* +* Only treat the last frequency that might be a boost +* as the boost frequency +*/ +if (prev_cc != max_cores) { + prev->frequency = prev_freq; + prev->flags =CPUFREQ_BOOST_FREQ ; + } + +break ; + } + + prev_cc = core_count; + prev_freq = freq; + } + + table[i].frequency =CPUFREQ_TABLE_END ; + policy->freq_table = table; + +return 0 ; +} + +static void qcom_get_related_cpus (int index,struct cpumask *m) +{ +struct device_node *cpu_np; +struct of_phandle_args args; +int cpu, ret; + +for_each_possible_cpu (cpu) { + cpu_np =of_cpu_device_node_get (cpu); +if (!cpu_np) +continue ; + + ret =of_parse_phandle_with_args (cpu_np,"qcom,freq-domain" , +"#freq-domain-cells" ,0 , + &args); +of_node_put (cpu_np); +if (ret <0 ) +continue ; + +if (index == args.args[0 ]) +cpumask_set_cpu (cpu, m); + } +} + +static int qcom_cpufreq_hw_cpu_init (struct cpufreq_policy *policy) +{ +struct device *dev = &global_pdev->dev; +struct of_phandle_args args; +struct device_node *cpu_np; +struct resource *res; +void __iomem *base; +int ret, index; + + cpu_np =of_cpu_device_node_get (policy->cpu); +if (!cpu_np) +return -EINVAL ; + + ret =of_parse_phandle_with_args (cpu_np,"qcom,freq-domain" , +"#freq-domain-cells" ,0 , &args); +of_node_put (cpu_np); +if (ret) +return ret; + + index = args.args[0 ]; + + res =platform_get_resource (global_pdev,IORESOURCE_MEM , index); +if (!res) +return -ENODEV ; + + base =devm_ioremap (dev, res->start,resource_size (res)); +if (!base) +return -ENOMEM ; + +/* HW should be in enabled state to proceed */ +if (!(readl_relaxed (base +REG_ENABLE ) &0x1 )) { +dev_err (dev,"Domain-%d cpufreq hardware not enabled\n" , index); + ret = -ENODEV ; + goto error; + } + +qcom_get_related_cpus (index, policy->cpus); +if (!cpumask_weight (policy->cpus)) { +dev_err (dev,"Domain-%d failed to get related CPUs\n" , index); + ret = -ENOENT ; + goto error; + } + + policy->driver_data = base +REG_PERF_STATE ; + + ret =qcom_cpufreq_hw_read_lut (dev, policy, base); +if (ret) { +dev_err (dev,"Domain-%d failed to read LUT\n" , index); + goto error; + } + + policy->fast_switch_possible = true; + +return 0 ; +error: +devm_iounmap (dev, base); +return ret; +} + +static int qcom_cpufreq_hw_cpu_exit (struct cpufreq_policy *policy) +{ +void __iomem *base = policy->driver_data -REG_PERF_STATE ; + +kfree (policy->freq_table); +devm_iounmap (&global_pdev->dev, base); + +return 0 ; +} + +static struct freq_attr *qcom_cpufreq_hw_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + &cpufreq_freq_attr_scaling_boost_freqs, +NULL +}; + +static struct cpufreq_driver cpufreq_qcom_hw_driver = { + .flags =CPUFREQ_STICKY |CPUFREQ_NEED_INITIAL_FREQ_CHECK | +CPUFREQ_HAVE_GOVERNOR_PER_POLICY , + .verify = cpufreq_generic_frequency_table_verify, + .target_index = qcom_cpufreq_hw_target_index, + .get = qcom_cpufreq_hw_get, + .init = qcom_cpufreq_hw_cpu_init, + .exit = qcom_cpufreq_hw_cpu_exit, + .fast_switch = qcom_cpufreq_hw_fast_switch, + .name ="qcom-cpufreq-hw" , + .attr = qcom_cpufreq_hw_attr, +}; + +static int qcom_cpufreq_hw_driver_probe (struct platform_device *pdev) +{ +struct clk *clk; +int ret; + + clk =clk_get (&pdev->dev,"xo" ); +if (IS_ERR (clk)) +return PTR_ERR (clk); + + xo_rate =clk_get_rate (clk); +clk_put (clk); + + clk =clk_get (&pdev->dev,"alternate" ); +if (IS_ERR (clk)) +return PTR_ERR (clk); + + cpu_hw_rate =clk_get_rate (clk) /CLK_HW_DIV ; +clk_put (clk); + + global_pdev = pdev; + + ret =cpufreq_register_driver (&cpufreq_qcom_hw_driver); +if (ret) +dev_err (&pdev->dev,"CPUFreq HW driver failed to register\n" ); +else +dev_dbg (&pdev->dev,"QCOM CPUFreq HW driver initialized\n" ); + +return ret; +} + +static int qcom_cpufreq_hw_driver_remove (struct platform_device *pdev) +{ +return cpufreq_unregister_driver (&cpufreq_qcom_hw_driver); +} + +static const struct of_device_id qcom_cpufreq_hw_match[] = { + { .compatible ="qcom,cpufreq-hw" }, + {} +}; +MODULE_DEVICE_TABLE (of, qcom_cpufreq_hw_match); + +static struct platform_driver qcom_cpufreq_hw_driver = { + .probe = qcom_cpufreq_hw_driver_probe, + .remove = qcom_cpufreq_hw_driver_remove, + .driver = { + .name ="qcom-cpufreq-hw" , + .of_match_table = qcom_cpufreq_hw_match, + }, +}; + +static int __init qcom_cpufreq_hw_init (void ) +{ +return platform_driver_register (&qcom_cpufreq_hw_driver); +}
drivers/cpufreq/qcom-cpufreq-hw.c line 308
Quoted 10 lines
drivers/cpufreq/qcom-cpufreq-hw.c new file +10
-0+subsys_initcall (qcom_cpufreq_hw_init); + +static void __exit qcom_cpufreq_hw_exit(void) +{ +platform_driver_unregister (&qcom_cpufreq_hw_driver); +} +module_exit (qcom_cpufreq_hw_exit); + +MODULE_DESCRIPTION ("QCOM CPUFREQ HW Driver" ); +MODULE_LICENSE ("GPL v2" );
Re: [PATCH v13 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
In reply to Taniya DasQuoted 8 lines · Taniya Das
The CPUfreq HW present in some QCOM chipsets offloads the steps necessary for changing the frequency of CPUs. The driver implements the cpufreq driver interface for this hardware engine.
Signed-off-by Saravana Kannan <[email protected]>Signed-off-by Stephen Boyd <[email protected]>Signed-off-by Taniya Das <[email protected]>
Quoted 359 lines
--- drivers/cpufreq/Kconfig.arm | 11 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 308 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 320 insertions(+) create mode 100644 drivers/cpufreq/qcom-cpufreq-hw.cdrivers/cpufreq/Kconfig.arm +11
-0@@ -114,6 +114,17 @@ config ARM_QCOM_CPUFREQ_KRYO If in doubt, say N. +config ARM_QCOM_CPUFREQ_HW + tristate "QCOM CPUFreq HW driver" + depends on ARCH_QCOM || COMPILE_TEST + help + Support for the CPUFreq HW driver. + Some QCOM chipsets have a HW engine to offload the steps + necessary for changing the frequency of the CPUs. Firmware loaded + in this engine exposes a programming interface to the OS. + The driver implements the cpufreq interface for this HW engine. + Say Y if you want to support CPUFreq HW. + config ARM_S3C_CPUFREQ bool helpdrivers/cpufreq/Makefile +1
-0@@ -61,6 +61,7 @@ obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.odrivers/cpufreq/qcom-cpufreq-hw.c new file +308
-1@@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* Copyright (c) 2018, The Linux Foundation. All rights reserved. +*/ + +#include <linux/bitfield.h> +#include <linux/cpufreq.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/slab.h> + +#define LUT_MAX_ENTRIES 40U +#define LUT_SRC GENMASK(31, 30) +#define LUT_L_VAL GENMASK(7, 0) +#define LUT_CORE_COUNT GENMASK(18, 16) +#define LUT_ROW_SIZE 32 +#define CLK_HW_DIV 2 + +/* Register offsets */ +#define REG_ENABLE 0x0 +#define REG_LUT_TABLE 0x110 +#define REG_PERF_STATE 0x920 + +static unsigned long cpu_hw_rate, xo_rate; +static struct platform_device *global_pdev; + +static int qcom_cpufreq_hw_target_index (struct cpufreq_policy *policy, +unsigned int index) +{ +void __iomem *perf_state_reg = policy->driver_data; + +writel_relaxed (index, perf_state_reg); + +return 0 ; +} + +static unsigned int qcom_cpufreq_hw_get (unsigned int cpu) +{ +void __iomem *perf_state_reg; +struct cpufreq_policy *policy; +unsigned int index; + + policy =cpufreq_cpu_get_raw (cpu); +if (!policy) +return 0 ; + + perf_state_reg = policy->driver_data; + + index =readl_relaxed (perf_state_reg); + index =min (index,LUT_MAX_ENTRIES -1 ); + +return policy->freq_table[index].frequency; +} + +static unsigned int qcom_cpufreq_hw_fast_switch (struct cpufreq_policy *policy, +unsigned int target_freq) +{ +void __iomem *perf_state_reg = policy->driver_data; +int index; + + index = policy->cached_resolved_idx; +if (index <0 ) +return 0 ; + +writel_relaxed (index, perf_state_reg); + +return policy->freq_table[index].frequency; +} + +static int qcom_cpufreq_hw_read_lut (struct device *dev, +struct cpufreq_policy *policy, +void __iomem *base) +{ +u32 data, src, lval, i, core_count, prev_cc =0 , prev_freq =0 , freq; +unsigned int max_cores =cpumask_weight (policy->cpus); +struct cpufreq_frequency_table *table; + + table =kcalloc (LUT_MAX_ENTRIES +1 ,sizeof (*table),GFP_KERNEL ); +if (!table) +return -ENOMEM ; + +for (i =0 ; i <LUT_MAX_ENTRIES ; i++) { + data =readl_relaxed (base +REG_LUT_TABLE + i *LUT_ROW_SIZE ); + src =FIELD_GET (LUT_SRC , data); + lval =FIELD_GET (LUT_L_VAL , data); + core_count =FIELD_GET (LUT_CORE_COUNT , data); + +if (src) + freq = xo_rate * lval /1000 ; +else + freq = cpu_hw_rate /1000 ; + +/* Ignore boosts in the middle of the table */ +if (core_count != max_cores) { + table[i].frequency =CPUFREQ_ENTRY_INVALID ; + }else { + table[i].frequency = freq; +dev_dbg (dev,"index=%d freq=%d, core_count %d\n" , i, + freq, core_count); + } + +/* +* Two of the same frequencies with the same core counts means +* end of table +*/ +if (i >0 && prev_freq == freq && prev_cc == core_count) { +struct cpufreq_frequency_table *prev = &table[i -1 ]; + +/* +* Only treat the last frequency that might be a boost +* as the boost frequency +*/ +if (prev_cc != max_cores) { + prev->frequency = prev_freq; + prev->flags =CPUFREQ_BOOST_FREQ ; + } + +break ; + } + + prev_cc = core_count; + prev_freq = freq; + } + + table[i].frequency =CPUFREQ_TABLE_END ; + policy->freq_table = table; + +return 0 ; +} + +static void qcom_get_related_cpus (int index,struct cpumask *m) +{ +struct device_node *cpu_np; +struct of_phandle_args args; +int cpu, ret; + +for_each_possible_cpu (cpu) { + cpu_np =of_cpu_device_node_get (cpu); +if (!cpu_np) +continue ; + + ret =of_parse_phandle_with_args (cpu_np,"qcom,freq-domain" , +"#freq-domain-cells" ,0 , + &args); +of_node_put (cpu_np); +if (ret <0 ) +continue ; + +if (index == args.args[0 ]) +cpumask_set_cpu (cpu, m); + } +} + +static int qcom_cpufreq_hw_cpu_init (struct cpufreq_policy *policy) +{ +struct device *dev = &global_pdev->dev; +struct of_phandle_args args; +struct device_node *cpu_np; +struct resource *res; +void __iomem *base; +int ret, index; + + cpu_np =of_cpu_device_node_get (policy->cpu); +if (!cpu_np) +return -EINVAL ; + + ret =of_parse_phandle_with_args (cpu_np,"qcom,freq-domain" , +"#freq-domain-cells" ,0 , &args); +of_node_put (cpu_np); +if (ret) +return ret; + + index = args.args[0 ]; + + res =platform_get_resource (global_pdev,IORESOURCE_MEM , index); +if (!res) +return -ENODEV ; + + base =devm_ioremap (dev, res->start,resource_size (res)); +if (!base) +return -ENOMEM ; + +/* HW should be in enabled state to proceed */ +if (!(readl_relaxed (base +REG_ENABLE ) &0x1 )) { +dev_err (dev,"Domain-%d cpufreq hardware not enabled\n" , index); + ret = -ENODEV ; + goto error; + } + +qcom_get_related_cpus (index, policy->cpus); +if (!cpumask_weight (policy->cpus)) { +dev_err (dev,"Domain-%d failed to get related CPUs\n" , index); + ret = -ENOENT ; + goto error; + } + + policy->driver_data = base +REG_PERF_STATE ; + + ret =qcom_cpufreq_hw_read_lut (dev, policy, base); +if (ret) { +dev_err (dev,"Domain-%d failed to read LUT\n" , index); + goto error; + } + + policy->fast_switch_possible = true; + +return 0 ; +error: +devm_iounmap (dev, base); +return ret; +} + +static int qcom_cpufreq_hw_cpu_exit (struct cpufreq_policy *policy) +{ +void __iomem *base = policy->driver_data -REG_PERF_STATE ; + +kfree (policy->freq_table); +devm_iounmap (&global_pdev->dev, base); + +return 0 ; +} + +static struct freq_attr *qcom_cpufreq_hw_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + &cpufreq_freq_attr_scaling_boost_freqs, +NULL +}; + +static struct cpufreq_driver cpufreq_qcom_hw_driver = { + .flags =CPUFREQ_STICKY |CPUFREQ_NEED_INITIAL_FREQ_CHECK | +CPUFREQ_HAVE_GOVERNOR_PER_POLICY , + .verify = cpufreq_generic_frequency_table_verify, + .target_index = qcom_cpufreq_hw_target_index, + .get = qcom_cpufreq_hw_get, + .init = qcom_cpufreq_hw_cpu_init, + .exit = qcom_cpufreq_hw_cpu_exit, + .fast_switch = qcom_cpufreq_hw_fast_switch, + .name ="qcom-cpufreq-hw" , + .attr = qcom_cpufreq_hw_attr, +}; + +static int qcom_cpufreq_hw_driver_probe (struct platform_device *pdev) +{ +struct clk *clk; +int ret; + + clk =clk_get (&pdev->dev,"xo" ); +if (IS_ERR (clk)) +return PTR_ERR (clk); + + xo_rate =clk_get_rate (clk); +clk_put (clk); + + clk =clk_get (&pdev->dev,"alternate" ); +if (IS_ERR (clk)) +return PTR_ERR (clk); + + cpu_hw_rate =clk_get_rate (clk) /CLK_HW_DIV ; +clk_put (clk); + + global_pdev = pdev; + + ret =cpufreq_register_driver (&cpufreq_qcom_hw_driver); +if (ret) +dev_err (&pdev->dev,"CPUFreq HW driver failed to register\n" ); +else +dev_dbg (&pdev->dev,"QCOM CPUFreq HW driver initialized\n" ); + +return ret; +} + +static int qcom_cpufreq_hw_driver_remove (struct platform_device *pdev) +{ +return cpufreq_unregister_driver (&cpufreq_qcom_hw_driver); +} + +static const struct of_device_id qcom_cpufreq_hw_match[] = { + { .compatible ="qcom,cpufreq-hw" }, + {} +}; +MODULE_DEVICE_TABLE (of, qcom_cpufreq_hw_match); + +static struct platform_driver qcom_cpufreq_hw_driver = { + .probe = qcom_cpufreq_hw_driver_probe, + .remove = qcom_cpufreq_hw_driver_remove, + .driver = { + .name ="qcom-cpufreq-hw" , + .of_match_table = qcom_cpufreq_hw_match, + }, +}; + +static int __init qcom_cpufreq_hw_init (void ) +{ +return platform_driver_register (&qcom_cpufreq_hw_driver); +} +subsys_initcall (qcom_cpufreq_hw_init); + +static void __exit qcom_cpufreq_hw_exit(void) +{ +platform_driver_unregister (&qcom_cpufreq_hw_driver); +} +module_exit (qcom_cpufreq_hw_exit); + +MODULE_DESCRIPTION ("QCOM CPUFREQ HW Driver" ); +MODULE_LICENSE ("GPL v2" ); --Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Quoted 3 lines · Taniya Das
[v13]
* Update Documentation binding to #freq-domain-cells in description.
* Replacedevm_ioremap_resource()to usedevm_ioremap()API.
Signature · 1 line
viresh
Quoted 6 lines · CET Viresh Kumar
Quoted 3 lines · Taniya Das
[v13]
* Update Documentation binding to #freq-domain-cells in description.
* Replacedevm_ioremap_resource()to usedevm_ioremap()API.Acked-by Viresh Kumar <[email protected]>
The series has been applied, thanks!