Re: [PATCH v2 2/2] clk: qcom: Add lpass clock controller driver for SDM845
On 7/7/2018 5:09 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-07-04 23:55:21) diff --git a/drivers/clk/qcom/lpasscc-sdm845.c b/drivers/clk/qcom/lpasscc-sdm845.c new file mode 100644 index 000..5285b26 --- /dev/null +++ b/drivers/clk/qcom/lpasscc-sdm845.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-regmap.h" +#include "clk-branch.h" +#include "common.h" + +static struct clk_branch gcc_lpass_q6_axi_clk = { + .halt_reg = 0x0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_q6_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_lpass_sway_clk = { + .halt_reg = 0x8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_sway_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + Moved the above clocks to GCC driver. +static struct clk_branch lpass_audio_wrapper_aon_clk = { + .halt_reg = 0x098, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_audio_wrapper_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch lpass_q6ss_ahbm_aon_clk = { + .halt_reg = 0x12000, + .halt_check = BRANCH_VOTED, I'll take your word for it. + .clkr = { + .enable_reg = 0x12000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_q6ss_ahbm_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch lpass_q6ss_ahbs_aon_clk = { + .halt_reg = 0x1f000, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x1f000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_q6ss_ahbs_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch lpass_qdsp6ss_xo_clk = { + .halt_reg = 0x18, + .halt_check = BRANCH_HALT_SKIP, Why? Hint, add a comment. Added a comment in the next patch. + .clkr = { + .enable_reg = 0x18, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_qdsp6ss_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch lpass_qdsp6ss_sleep_clk = { + .halt_reg = 0x1c, + .halt_check = BRANCH_HALT_SKIP, Why? Hint, add a comment. Added a comment in the next patch. + .clkr = { + .enable_reg = 0x1c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_qdsp6ss_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch lpass_qdsp6ss_core_clk = { + .halt_reg = 0x0, + .halt_check = BRANCH_HALT_SKIP, Again. Added a comment in the next patch. + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_qdsp6ss_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct regmap_config lpass_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io= true, +}; + +static struct clk_regmap *lpass_gcc_sdm845_clocks[] = { + [GCC_LPASS_Q6_AXI_CLK] = &gcc_lpass_q6_axi_clk.clkr, + [GCC_LPASS_SWAY_CLK] = &gcc_lpass_sway_clk.clkr, +}; + +static const struct qcom_cc_desc lpass_gcc_sdm845_desc = { + .config = &lpass_regmap_config, + .clks = lpass_gcc_sdm845_clocks, + .num_clks = ARRAY_SIZE(lpass_gcc_sdm845_clocks), +}; + +static struct clk_regmap *lpass_cc_sdm845_clocks[] = { + [LPASS_AUDIO_WRAPPER_AON_CLK] = &lpass_audio_wrapper_aon_clk.clkr, + [LPASS_Q6SS_AHBM_AON_CLK] = &lpass_
Re: [PATCH v2 1/2] dt-bindings: clock: Introduce QCOM LPASS clock bindings
On 7/7/2018 5:12 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-07-04 23:55:20) diff --git a/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt new file mode 100644 index 000..fe7378b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt @@ -0,0 +1,22 @@ +Qualcomm LPASS Clock Controller Binding +--- + +Required properties : +- compatible : shall contain "qcom,sdm845-lpasscc" +- #clock-cells : from common clock binding, shall contain 1. +- reg : shall contain base register address and size. +- reg-names: shall contain the register names of LPASS domain + "lpass_gcc", "lpass_cc", "lpass_qdsp6ss". + +Example: + +The below node has to be defined in the cases where the LPASS peripheral loader +would bring the subsystem out of reset. + + lpasscc: clock-controller { + compatible = "qcom,sdm845-lpasscc"; + reg = <0x00147000 0x20>, <0x17014000 0x1f004>, This first reg is inside GCC though? Why isn't it added to the gcc sdm845 driver? And then the next two might make sense as a different region, but the reg property ending in 20 looks really weird. I have moved the GCC registers in the GCC driver with a device tree property flag. And also have mapped the lpass_qdsp6ss CC region. + <0x17300020 0x20>; + reg-names = "lpass_gcc", "lpass_cc", "lpass_qdsp6ss"; + #clock-cells = <1>; + }; -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v3 1/2] dt-bindings: clock: Introduce QCOM LPASS clock bindings
Add device tree bindings for Low Power Audio subsystem clock controller for Qualcomm Technology Inc's SDM845 SoCs. Signed-off-by: Taniya Das --- .../devicetree/bindings/clock/qcom,gcc.txt | 2 ++ .../devicetree/bindings/clock/qcom,lpasscc.txt | 33 ++ include/dt-bindings/clock/qcom,gcc-sdm845.h| 2 ++ include/dt-bindings/clock/qcom,lpass-sdm845.h | 16 +++ 4 files changed, 53 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lpasscc.txt create mode 100644 include/dt-bindings/clock/qcom,lpass-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 664ea1f..e452abc 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -32,6 +32,8 @@ be part of GCC and hence the TSENS properties can also be part of the GCC/clock-controller node. For more details on the TSENS properties please refer Documentation/devicetree/bindings/thermal/qcom-tsens.txt +- qcom,lpass-protected : Indicate GCC to be able to access the + lpass gcc clock branches. Example: clock-controller@90 { diff --git a/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt new file mode 100644 index 000..062e413 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt @@ -0,0 +1,33 @@ +Qualcomm LPASS Clock Controller Binding +--- + +Required properties : +- compatible : shall contain "qcom,sdm845-lpasscc" +- #clock-cells : from common clock binding, shall contain 1. +- reg : shall contain base register address and size, + in the order + Index-0 maps to LPASS_CC register region + Index-1 maps to LPASS_QDSP6SS register region +- qcom,lpass-protected : Boolean property to indicate to GCC clock controller +for the lpass GCC clocks. + +Optional properties : +- reg-names: register names of LPASS domain +"lpass_cc", "lpass_qdsp6ss". + +Example: + +The below node has to be defined in the cases where the LPASS peripheral loader +would bring the subsystem out of reset. + + lpasscc: clock-controller { + compatible = "qcom,sdm845-lpasscc"; + reg = <0x17014000 0x1f004>, <0x1730 0x200>; + reg-names = "lpass_cc", "lpass_qdsp6ss"; + #clock-cells = <1>; + }; + + gcc: clock-controller@10 { + compatible = "qcom,gcc-sdm845"; + qcom,lpass-protected; + }; diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h index f96fc2d..66c4267 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h @@ -194,6 +194,8 @@ #define GPLL4 184 #define GCC_CPUSS_DVM_BUS_CLK 185 #define GCC_CPUSS_GNOC_CLK 186 +#define GCC_LPASS_Q6_AXI_CLK 187 +#define GCC_LPASS_SWAY_CLK 188 /* GCC Resets */ #define GCC_MMSS_BCR 0 diff --git a/include/dt-bindings/clock/qcom,lpass-sdm845.h b/include/dt-bindings/clock/qcom,lpass-sdm845.h new file mode 100644 index 000..015968e --- /dev/null +++ b/include/dt-bindings/clock/qcom,lpass-sdm845.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H +#define _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H + +#define LPASS_AUDIO_WRAPPER_AON_CLK0 +#define LPASS_Q6SS_AHBM_AON_CLK1 +#define LPASS_Q6SS_AHBS_AON_CLK2 +#define LPASS_QDSP6SS_XO_CLK 3 +#define LPASS_QDSP6SS_SLEEP_CLK4 +#define LPASS_QDSP6SS_CORE_CLK 5 + +#endif -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v3 0/2] Add support for LPASS clock controller for SDM845
[v3] * Add a device tree property to identify lpass protected GCC clocks. * Update the GCC driver code to register the lpass clocks when the flag is defined. * Add comment for clocks using the BRANCH_HALT_SKIP flag. * Use platform APIs instead of of_address_to_resource. * Replace devm_ioremap with devm_ioremap_resource. * Use fixed index for 'lpass_cc' & 'lpass_qdsp6ss' in probe. [v2] * Make gcc_lpass_sway_clk static. * Remove using child nodes and use reg-names to differentiate various domains of LPASS CC. Add support for the lpass clock controller found on SDM845 based devices. This would allow lpass peripheral loader drivers to control the clocks to bring the subsystem out of reset. Taniya Das (2): dt-bindings: clock: Introduce QCOM LPASS clock bindings clk: qcom: Add lpass clock controller driver for SDM845 .../devicetree/bindings/clock/qcom,gcc.txt | 2 + .../devicetree/bindings/clock/qcom,lpasscc.txt | 33 drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sdm845.c | 35 drivers/clk/qcom/lpasscc-sdm845.c | 189 + include/dt-bindings/clock/qcom,gcc-sdm845.h| 2 + include/dt-bindings/clock/qcom,lpass-sdm845.h | 16 ++ 8 files changed, 287 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lpasscc.txt create mode 100644 drivers/clk/qcom/lpasscc-sdm845.c create mode 100644 include/dt-bindings/clock/qcom,lpass-sdm845.h -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v3 2/2] clk: qcom: Add lpass clock controller driver for SDM845
Add support for the lpass clock controller found on SDM845 based devices. This would allow lpass peripheral loader drivers to control the clocks to bring the subsystem out of reset. LPASS clocks present on the global clock controller would be registered with the clock framework based on the device tree flag. Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 9 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sdm845.c | 35 +++ drivers/clk/qcom/lpasscc-sdm845.c | 189 ++ 4 files changed, 234 insertions(+) create mode 100644 drivers/clk/qcom/lpasscc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 2b69cf2..7bd940d 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -254,6 +254,15 @@ config SDM_VIDEOCC_845 Say Y if you want to support video devices and functionality such as video encode and decode. +config SDM_LPASSCC_845 + tristate "SDM845 LPASS Clock Controller" + depends on COMMON_CLK_QCOM + select SDM_GCC_845 + help + Support for the LPASS clock controller on SDM845 devices. + Say Y if you want to use the LPASS branch clocks of the LPASS clock + controller to reset the LPASS subsystem. + config SPMI_PMIC_CLKDIV tristate "SPMI PMIC clkdiv Support" depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 599ab91..df2bd1f 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -40,5 +40,6 @@ obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o +obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 0f694ed..068cf53 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -3086,6 +3086,32 @@ enum { }, }; +static struct clk_branch gcc_lpass_q6_axi_clk = { + .halt_reg = 0x47000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_q6_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_lpass_sway_clk = { + .halt_reg = 0x47008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_sway_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, .pd = { @@ -3383,6 +3409,8 @@ enum { [GPLL4] = &gpll4.clkr, [GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr, [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, + [GCC_LPASS_Q6_AXI_CLK] = NULL, + [GCC_LPASS_SWAY_CLK] = NULL, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { @@ -3472,6 +3500,13 @@ static int gcc_sdm845_probe(struct platform_device *pdev) regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3); regmap_update_bits(regmap, 0x71028, 0x3, 0x3); + if (of_property_read_bool(pdev->dev.of_node, "qcom,lpass-protected")) { + gcc_sdm845_clocks[GCC_LPASS_Q6_AXI_CLK] = + &gcc_lpass_q6_axi_clk.clkr; + gcc_sdm845_clocks[GCC_LPASS_SWAY_CLK] = + &gcc_lpass_sway_clk.clkr; + } + return qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap); } diff --git a/drivers/clk/qcom/lpasscc-sdm845.c b/drivers/clk/qcom/lpasscc-sdm845.c new file mode 100644 index 000..6f387f9 --- /dev/null +++ b/drivers/clk/qcom/lpasscc-sdm845.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-regmap.h" +#include "clk-branch.h" +#include "common.h" + +static struct clk_branch lpass_audio_wrapper_aon_clk = { + .halt_reg = 0x098, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_audio_wrapper_aon_clk", + .ops = &clk_branch2_ops, + },
Re: [PATCH v7 1/2] dt-bindings: cpufreq: Introduce QCOM CPUFREQ Firmware bindings
On 8/8/2018 12:54 AM, skan...@codeaurora.org wrote: On 2018-08-07 04:12, Sudeep Holla wrote: On Mon, Aug 06, 2018 at 01:54:24PM -0700, skan...@codeaurora.org wrote: On 2018-08-03 16:46, Stephen Boyd wrote: >Quoting Taniya Das (2018-07-24 03:42:49) >>diff --git >>a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt >>b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt >>new file mode 100644 >>index 000..22d4355 >>--- /dev/null >>+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt >>@@ -0,0 +1,172 @@ >[...] >>+ >>+ CPU7: cpu@700 { >>+ device_type = "cpu"; >>+ compatible = "qcom,kryo385"; >>+ reg = <0x0 0x700>; >>+ enable-method = "psci"; >>+ next-level-cache = <&L2_700>; >>+ qcom,freq-domain = <&freq_domain_table1>; >>+ L2_700: l2-cache { >>+ compatible = "cache"; >>+ next-level-cache = <&L3_0>; >>+ }; >>+ }; >>+ }; >>+ >>+ qcom,cpufreq-hw { >>+ compatible = "qcom,cpufreq-hw"; >>+ >>+ clocks = <&rpmhcc RPMH_CXO_CLK>; >>+ clock-names = "xo"; >>+ >>+ #address-cells = <2>; >>+ #size-cells = <2>; >>+ ranges; >>+ freq_domain_table0: freq_table0 { >>+ reg = <0 0x17d43000 0 0x1400>; >>+ }; >>+ >>+ freq_domain_table1: freq_table1 { >>+ reg = <0 0x17d45800 0 0x1400>; >>+ }; > >Sorry, this is just not proper DT design. The whole node should have a >reg property, and it should contain two (or three if we're handling the >L3 clk domain?) different offsets for the different power clusters. The >problem seems to still be that we don't have a way to map the CPUs to >the clk domains they're in provided by this hardware block. Making >subnodes is not the solution. The problem is mapping clock domains to logical CPUs that CPUfreq uses. The physical CPU to logical CPU mapping can be changed by the kernel (even through DT if I'm not mistaken). So we need to have a way to tell in DT which physical CPUs are connected to which CPU freq clock domain. How about passing CPU freq clock domain id as along with phandle in qcom,freq-domain ? Now sure what you mean here. There's no such this as CPUfreq clock domain id. It has policies that are made up of logical CPU numbers. Logical CPU is not something that you can fix in DT. -Saravana Sudeep, Earlier the design was the freq_domain would take the CPU phandles freq_domain: cpus = <&cpu0 &cpu1>; -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v3 0/3] Add display clock controller driver for SDM845
[v3] * Move frequency table macro to common file, add the patch along to maintain dependency. [v2] * Removed unused header file includes. * Moved the frequency table macro to a common file [1]. * Move to pll config to probe. * Update SoC name in device tree binding and also update the Kconfig. Add support for the display clock controller found on SDM845 based devices. This would allow display drivers to probe and control their clocks. Taniya Das (3): clk: qcom: Move frequency table macro to common file dt-bindings: clock: Introduce QCOM Display clock bindings clk: qcom: Add display clock controller driver for SDM845 .../devicetree/bindings/clock/qcom,dispcc.txt | 19 + drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-rcg.h | 2 + drivers/clk/qcom/dispcc-sdm845.c | 674 + drivers/clk/qcom/gcc-apq8084.c | 2 - drivers/clk/qcom/gcc-ipq4019.c | 2 - drivers/clk/qcom/gcc-ipq8074.c | 2 - drivers/clk/qcom/gcc-msm8916.c | 2 - drivers/clk/qcom/gcc-msm8974.c | 2 - drivers/clk/qcom/gcc-msm8994.c | 2 - drivers/clk/qcom/gcc-msm8996.c | 2 - drivers/clk/qcom/gcc-msm8998.c | 2 - drivers/clk/qcom/gcc-sdm845.c | 2 - drivers/clk/qcom/mmcc-apq8084.c| 2 - drivers/clk/qcom/mmcc-msm8974.c| 2 - drivers/clk/qcom/mmcc-msm8996.c| 2 - drivers/clk/qcom/videocc-sdm845.c | 2 - include/dt-bindings/clock/qcom,dispcc-sdm845.h | 45 ++ 19 files changed, 751 insertions(+), 26 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/qcom,dispcc.txt create mode 100644 drivers/clk/qcom/dispcc-sdm845.c create mode 100644 include/dt-bindings/clock/qcom,dispcc-sdm845.h -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v3 1/3] clk: qcom: Move frequency table macro to common file
Frequency table macro is used by multiple clock drivers, move frequency table macro to common header file. Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-rcg.h| 2 ++ drivers/clk/qcom/gcc-apq8084.c| 2 -- drivers/clk/qcom/gcc-ipq4019.c| 2 -- drivers/clk/qcom/gcc-ipq8074.c| 2 -- drivers/clk/qcom/gcc-msm8916.c| 2 -- drivers/clk/qcom/gcc-msm8974.c| 2 -- drivers/clk/qcom/gcc-msm8994.c| 2 -- drivers/clk/qcom/gcc-msm8996.c| 2 -- drivers/clk/qcom/gcc-msm8998.c| 2 -- drivers/clk/qcom/gcc-sdm845.c | 2 -- drivers/clk/qcom/mmcc-apq8084.c | 2 -- drivers/clk/qcom/mmcc-msm8974.c | 2 -- drivers/clk/qcom/mmcc-msm8996.c | 2 -- drivers/clk/qcom/videocc-sdm845.c | 2 -- 14 files changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index b209a2f..dbd5a9e 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -7,6 +7,8 @@ #include #include "clk-regmap.h" +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + struct freq_tbl { unsigned long freq; u8 src; diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c index 486d961..9c99a71 100644 --- a/drivers/clk/qcom/gcc-apq8084.c +++ b/drivers/clk/qcom/gcc-apq8084.c @@ -106,8 +106,6 @@ enum { "sleep_clk_src", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_pll gpll0 = { .l_reg = 0x0004, .m_reg = 0x0008, diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c index 46cb256..8902ad4 100644 --- a/drivers/clk/qcom/gcc-ipq4019.c +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -179,8 +179,6 @@ struct clk_fepll { "ddrpllapss", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static const struct freq_tbl ftbl_gcc_audio_pwm_clk[] = { F(4800, P_XO, 1, 0, 0), F(2, P_FEPLL200, 1, 0, 0), diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c index 0462f4a..505c626 100644 --- a/drivers/clk/qcom/gcc-ipq8074.c +++ b/drivers/clk/qcom/gcc-ipq8074.c @@ -32,8 +32,6 @@ #include "clk-regmap-mux.h" #include "reset.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_XO, P_GPLL0, diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index d6c7f50..ac2b0aa 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -264,8 +264,6 @@ enum { "sleep_clk", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_pll gpll0 = { .l_reg = 0x21004, .m_reg = 0x21008, diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index 348e30d..08e2900d 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -62,8 +62,6 @@ enum { "gpll4_vote", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_pll gpll0 = { .l_reg = 0x0004, .m_reg = 0x0008, diff --git a/drivers/clk/qcom/gcc-msm8994.c b/drivers/clk/qcom/gcc-msm8994.c index 1e38efc..53f0f36 100644 --- a/drivers/clk/qcom/gcc-msm8994.c +++ b/drivers/clk/qcom/gcc-msm8994.c @@ -57,8 +57,6 @@ enum { "gpll4", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk_fixed_factor xo = { .mult = 1, .div = 1, diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 9f35b3f..9d3756c 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -32,8 +32,6 @@ #include "reset.h" #include "gdsc.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_XO, P_GPLL0, diff --git a/drivers/clk/qcom/gcc-msm8998.c b/drivers/clk/qcom/gcc-msm8998.c index 78d87f5..9f0ae40 100644 --- a/drivers/clk/qcom/gcc-msm8998.c +++ b/drivers/clk/qcom/gcc-msm8998.c @@ -25,8 +25,6 @@ #include "reset.h" #include "gdsc.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_AUD_REF_CLK, P_CORE_BI_PLL_TEST_SE, diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index e78e6f5..19b470f 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -25,8 +25,6 @@ #include "gdsc.h" #include "reset.h" -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - enum { P_BI_TCXO, P_AUD_REF_CLK, diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index 30777f9..4ce1d7c 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c @@ -219,8 +219,6 @@ enum { "sleep_clk_src", }; -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - static struct clk
[PATCH v3 3/3] clk: qcom: Add display clock controller driver for SDM845
Add support for the display clock controller found on SDM845 based devices. This would allow display drivers to probe and control their clocks. Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile| 1 + drivers/clk/qcom/dispcc-sdm845.c | 674 +++ 3 files changed, 685 insertions(+) create mode 100644 drivers/clk/qcom/dispcc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 9c3480d..7300574 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -245,6 +245,16 @@ config SDM_VIDEOCC_845 Say Y if you want to support video devices and functionality such as video encode and decode. +config SDM_DISPCC_845 + tristate "SDM845 Display Clock Controller" + select SDM_GCC_845 + depends on COMMON_CLK_QCOM + help + Support for the display clock controller on Qualcomm Technologies, Inc + SDM845 devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config SPMI_PMIC_CLKDIV tristate "SPMI PMIC clkdiv Support" depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 762c011..2b041b2d 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o +obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c new file mode 100644 index 000..af437e0 --- /dev/null +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap-divider.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_DISP_CC_PLL0_OUT_MAIN, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, +}; + +static const struct parent_map disp_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_0[] = { + "bi_tcxo", + "dsi0_phy_pll_out_byteclk", + "dsi1_phy_pll_out_byteclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_2[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN_DIV, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_3[] = { + "bi_tcxo", + "disp_cc_pll0", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_4[] = { + "bi_tcxo", + "dsi0_phy_pll_out_dsiclk", + "dsi1_phy_pll_out_dsiclk", + "core_bi_pll_test_se", +}; + +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x20d0, + .mnd_width = 0, + .hid_width = 5, +
[PATCH v3 2/3] dt-bindings: clock: Introduce QCOM Display clock bindings
Add device tree bindings for display clock controller for Qualcomm Technology Inc's SDM845 SoCs. Signed-off-by: Taniya Das Reviewed-by: Rob Herring --- .../devicetree/bindings/clock/qcom,dispcc.txt | 19 + include/dt-bindings/clock/qcom,dispcc-sdm845.h | 45 ++ 2 files changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,dispcc.txt create mode 100644 include/dt-bindings/clock/qcom,dispcc-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt new file mode 100644 index 000..d639e18 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt @@ -0,0 +1,19 @@ +Qualcomm Technologies, Inc. Display Clock Controller Binding + + +Required properties : + +- compatible : shall contain "qcom,sdm845-dispcc" +- reg : shall contain base register location and length. +- #clock-cells : from common clock binding, shall contain 1. +- #reset-cells : from common reset binding, shall contain 1. +- #power-domain-cells : from generic power domain binding, shall contain 1. + +Example: + dispcc: clock-controller@af0 { + compatible = "qcom,sdm845-dispcc"; + reg = <0xaf0 0x10>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,dispcc-sdm845.h b/include/dt-bindings/clock/qcom,dispcc-sdm845.h new file mode 100644 index 000..11eed4b --- /dev/null +++ b/include/dt-bindings/clock/qcom,dispcc-sdm845.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_DISP_CC_SDM845_H +#define _DT_BINDINGS_CLK_SDM_DISP_CC_SDM845_H + +/* DISP_CC clock registers */ +#define DISP_CC_MDSS_AHB_CLK 0 +#define DISP_CC_MDSS_AXI_CLK 1 +#define DISP_CC_MDSS_BYTE0_CLK 2 +#define DISP_CC_MDSS_BYTE0_CLK_SRC 3 +#define DISP_CC_MDSS_BYTE0_INTF_CLK4 +#define DISP_CC_MDSS_BYTE1_CLK 5 +#define DISP_CC_MDSS_BYTE1_CLK_SRC 6 +#define DISP_CC_MDSS_BYTE1_INTF_CLK7 +#define DISP_CC_MDSS_ESC0_CLK 8 +#define DISP_CC_MDSS_ESC0_CLK_SRC 9 +#define DISP_CC_MDSS_ESC1_CLK 10 +#define DISP_CC_MDSS_ESC1_CLK_SRC 11 +#define DISP_CC_MDSS_MDP_CLK 12 +#define DISP_CC_MDSS_MDP_CLK_SRC 13 +#define DISP_CC_MDSS_MDP_LUT_CLK 14 +#define DISP_CC_MDSS_PCLK0_CLK 15 +#define DISP_CC_MDSS_PCLK0_CLK_SRC 16 +#define DISP_CC_MDSS_PCLK1_CLK 17 +#define DISP_CC_MDSS_PCLK1_CLK_SRC 18 +#define DISP_CC_MDSS_ROT_CLK 19 +#define DISP_CC_MDSS_ROT_CLK_SRC 20 +#define DISP_CC_MDSS_RSCC_AHB_CLK 21 +#define DISP_CC_MDSS_RSCC_VSYNC_CLK22 +#define DISP_CC_MDSS_VSYNC_CLK 23 +#define DISP_CC_MDSS_VSYNC_CLK_SRC 24 +#define DISP_CC_PLL0 25 +#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 26 +#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 27 + +/* DISP_CC Reset */ +#define DISP_CC_MDSS_RSCC_BCR 0 + +/* DISP_CC GDSCR */ +#define MDSS_GDSC 0 + +#endif -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Re: [PATCH v2 0/2] Add display clock controller driver for SDM845
Hello Stephen, Thanks for the comments. On 6/19/2018 8:53 PM, Stephen Boyd wrote: Quoting Taniya Das (2018-06-13 03:33:15) [v2] * Removed unused header file includes. * Moved the frequency table macro to a common file [1]. * Move to pll config to probe. * Update SoC name in device tree binding and also update the Kconfig. Add support for the display clock controller found on SDM845 based devices. This would allow display drivers to probe and control their clocks. The Display clock driver depends on the frequency table macro movement to a common file [1]. Please send that patch along with these patches so the dependency is clear. Please check the latest patch series : https://lkml.org/lkml/2018/6/23/109 [1]: https://lkml.org/lkml/2018/6/13/216 -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
On 8/28/2018 2:34 AM, Stephen Boyd wrote: Quoting Stephen Boyd (2018-08-23 11:25:41) Quoting Taniya Das (2018-08-22 03:28:31) H. Ok. That won't work then. recalc_rate() better not try to populate the frequency table then or it will not work. So I suppose it needs to fallback to reading the registers and assuming the parent_rate coming in is the actual frequency of it's parent until the frequency table pointer is non-NULL. Would that work? Yes that would work. Ok. BTW, does DFS switch parents without software knowing about it? DFS would not switch until a HW request is sent, but SW would be unware of the switch except the current_perf_state being updated with the requested level. What happens in that case? Does the QUP driver make sure that the new parent of this RCG is properly enabled so that it can switch to it when needed? I am not sure if they poll for any of their QUP HW state to make sure the switch is complete. I'm still trying to understand this whole design. Who takes care of the voltage requirements in this case? The QUP driver as well? When the QUP driver requires to switch to new performance level, the first request would be to set_rate()(QUP driver would get the list of supported frequencies using the clk_round_rate()) which in QCOM clock driver would take care of setting the required voltage for the new parent switch. It would also make sure that the new parent is enabled if the QUP clk is enabled. That's another concern. Does the PLL turn on automatically when the RCG switches to it? Then the QUP driver would request the HW for a new perf switch which would result to a DFS switch for the QUP clocks. It sounds like the QUP driver does half of the work via the clk APIs and then the other half through the DFS register. Maybe the QUP driver should be registering a clk as well for its DFS register so it can all be clk API calls here. Something to consider. Anyway, that's not important to this patch so here's the updated patch. I've squashed this in and applied the patches. Thanks Stephen. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v7 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
On 8/8/2018 11:52 AM, Stephen Boyd wrote: Quoting skan...@codeaurora.org (2018-08-06 13:46:05) On 2018-08-03 15:24, Stephen Boyd wrote: Quoting skan...@codeaurora.org (2018-08-03 12:52:48) On 2018-08-03 12:40, Evan Green wrote: Hi Taniya, On Tue, Jul 24, 2018 at 3:44 AM Taniya Das wrote: + if (src) + c->table[i].frequency = c->xo_rate * lval / 1000; + else + c->table[i].frequency = INIT_RATE / 1000; I don't know much about how this hardware works, but based on the mask, src has 4 possible values. So does 0 mean INIT_RATE, and 1, 2, and 3 all mean xo_rate? Also, is INIT_RATE really constant? It sounds like gpll0 (or gpll0_out_even?). You're already getting the xo clock, why not get gpll0's real rate as well? Actually I was about to comment and say NOT to get clocks just to get their rate. The XO_RATE is just a multiplication factor. This HW/FW can change in the future and make the multiplication factor to 1KHz. So future changes to this hardware are going to make this register return the final frequency that we should use? Sounds great! But that isn't how it's working right now. We need to have XO in the binding here so the driver can work with different XO frequencies in case that ever happens. Same story for GPLL0. Hardcoding this stuff in the driver just means we'll have to swizzle things in the driver when it changes. XO being a different frequency in a Qualcomm chip is way way less likely than anything else we are discussing here. In the 10+years I've been there this has never changed. So, how about making this binding optional? If it's not present we can make assumptions for XO rate and init rate. That'll handle your hypothetical use case while also being optimized. Optional properties are almost never correct for clks. Either the clk goes there or it doesn't go there. The only time it's optional is if the HW has the choice of generating the clk itself internally or to use an external clk as input. In this case, it's not optional, it's actually used so marking it optional is highly confusing. We also can't really control any of the clocks going to this block from Linux (it's all locked down). This shouldn't matter. The clocks going to this hardware block are described by the firmware to the OS by means of the DT node. If the firmware or the hardware decides to change the input clks then the binding can have different clk nodes used. There are tons of clocks that are input to blocks in an SoC that are never controlled by Linux. Or are expose in DT because they are set up ahead of time and can't change. So, why make an exception here? Because the driver doesn't have to hard-code some frequency that can easily come from the DT, making it more flexible for frequency plan changes. It doesn't matter about control of clks at all here, so this comparison is just plain wrong. The INIT_RATE will always be 300 MHz independent of what source it's coming from (as in, if GPLL0 can't give 300, the HW design will be so that we'll find a different source). So, I'd like to remove any clock bindings for this driver. No. Bindings describe how the hardware is connected. Please don't remove clocks from the binding just because probe defer is a concern. Binding describes hardware controllable by the OS. That's the reality. Let's not add mandatory clock bindings for clocks that the OS can't do anything about. It seems that you believe clks should only be used to turn on/off and control rates. That is not the whole truth. Sometimes clks are there just to express the clk frequencies that are present in the design so that drivers can figure out what to do. Stephen, As this clock is not configurable by linux clock drivers and we really do not care the parent src(as mentioned by Saravana) to generate the 300MHz, would it be good to define a fixed rate clock so as to express the HW connectivity & frequency? -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v3 1/2] clk: qcom: Add qspi (Quad SPI) clock defines for sdm845 to header
On 7/25/2018 9:31 PM, Rob Herring wrote: On Tue, Jul 24, 2018 at 10:45:12AM -0700, Douglas Anderson wrote: These clocks will need to be defined in the clock driver and referenced in device tree files. Signed-off-by: Douglas Anderson --- Changes in v3: None Changes in v2: None include/dt-bindings/clock/qcom,gcc-sdm845.h | 3 +++ 1 file changed, 3 insertions(+) Acked-by: Rob Herring Reviewed-by: Taniya Das -- To unsubscribe from this list: send the line "unsubscribe linux-clk" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v3 2/2] clk: qcom: Add qspi (Quad SPI) clocks for sdm845
On 7/24/2018 11:15 PM, Douglas Anderson wrote: Add both the interface and core clock. Signed-off-by: Douglas Anderson (am from https://lore.kernel.org/patchwork/patch/966680/mbox) --- Changes in v3: - Removed gcc_parent_names_9 which I had left in (doh!). Changes in v2: - Only 19.2, 100, 150, and 300 MHz now. - All clocks come from MAIN rather than EVEN. - Use parent map 0 instead of new parent map 9. drivers/clk/qcom/gcc-sdm845.c | 56 +++ 1 file changed, 56 insertions(+) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 0f694ed4238a..fc1c6658ad82 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -358,6 +358,28 @@ static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = { }, }; +static const struct freq_tbl ftbl_gcc_qspi_core_clk_src[] = { + F(1920, P_BI_TCXO, 1, 0, 0), + F(1, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(15000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(3, P_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qspi_core_clk_src = { + .cmd_rcgr = 0x4b008, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qspi_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_core_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .ops = &clk_rcg2_floor_ops, + }, +}; + static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { F(960, P_BI_TCXO, 2, 0, 0), F(1920, P_BI_TCXO, 1, 0, 0), @@ -1935,6 +1957,37 @@ static struct clk_branch gcc_qmip_video_ahb_clk = { }, }; +static struct clk_branch gcc_qspi_cnoc_periph_ahb_clk = { + .halt_reg = 0x4b000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_cnoc_periph_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qspi_core_clk = { + .halt_reg = 0x4b004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4b004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_core_clk", + .parent_names = (const char *[]){ + "gcc_qspi_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_qupv3_wrap0_s0_clk = { .halt_reg = 0x17030, .halt_check = BRANCH_HALT_VOTED, @@ -3383,6 +3436,9 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GPLL4] = &gpll4.clkr, [GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr, [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, + [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr, + [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr, + [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { Reviewed-by: Taniya Das -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v4 2/2] clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845
QUPv3 clocks support DFS and thus register the RCGs which require support for the same. Signed-off-by: Taniya Das --- drivers/clk/qcom/gcc-sdm845.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index fa1a196..fef6732 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -3458,9 +3458,29 @@ enum { }; MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table); +static struct clk_rcg2 *gcc_dfs_clocks[] = { + &gcc_qupv3_wrap0_s0_clk_src, + &gcc_qupv3_wrap0_s1_clk_src, + &gcc_qupv3_wrap0_s2_clk_src, + &gcc_qupv3_wrap0_s3_clk_src, + &gcc_qupv3_wrap0_s4_clk_src, + &gcc_qupv3_wrap0_s5_clk_src, + &gcc_qupv3_wrap0_s6_clk_src, + &gcc_qupv3_wrap0_s7_clk_src, + &gcc_qupv3_wrap1_s0_clk_src, + &gcc_qupv3_wrap1_s1_clk_src, + &gcc_qupv3_wrap1_s2_clk_src, + &gcc_qupv3_wrap1_s3_clk_src, + &gcc_qupv3_wrap1_s4_clk_src, + &gcc_qupv3_wrap1_s5_clk_src, + &gcc_qupv3_wrap1_s6_clk_src, + &gcc_qupv3_wrap1_s7_clk_src, +}; + static int gcc_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; + int ret; regmap = qcom_cc_map(pdev, &gcc_sdm845_desc); if (IS_ERR(regmap)) @@ -3470,6 +3490,11 @@ static int gcc_sdm845_probe(struct platform_device *pdev) regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3); regmap_update_bits(regmap, 0x71028, 0x3, 0x3); + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) + return ret; + return qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap); } -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v4 1/2] clk: qcom: Add support for RCG to register for DFS
Dynamic Frequency switch is a feature of clock controller by which request from peripherals allows automatic switching frequency of input clock without SW intervention. There are various performance levels associated with a root clock. When the input performance state changes, the source clocks and division ratios of the new performance state are loaded on to RCG via HW and the RCG switches to new clock frequency when the RCG is in DFS HW enabled mode. Register the root clock generators(RCG) to switch to use the dfs clock ops in the cases where DFS is enabled. The clk_round_rate() called by the clock consumer would invoke the dfs determine clock ops and would read the DFS performance level registers to identify all the frequencies supported and update the frequency table. The DFS clock consumers would maintain these frequency mapping and request the desired performance levels. Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-rcg.h | 2 + drivers/clk/qcom/clk-rcg2.c | 224 2 files changed, 226 insertions(+) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index dbd5a9e..e6300e0 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -163,4 +163,6 @@ struct clk_rcg2 { extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_rcg2_shared_ops; +extern int qcom_cc_register_rcg_dfs(struct regmap *regmap, +struct clk_rcg2 **rcgs, int num_clks); #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 52208d4..55a5b58 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -40,6 +41,14 @@ #define N_REG 0xc #define D_REG 0x10 +/* Dynamic Frequency Scaling */ +#define MAX_PERF_LEVEL 8 +#define SE_CMD_DFSR_OFFSET 0x14 +#define SE_CMD_DFS_EN BIT(0) +#define SE_PERF_DFSR(level)(0x1c + 0x4 * (level)) +#define SE_PERF_M_DFSR(level) (0x5c + 0x4 * (level)) +#define SE_PERF_N_DFSR(level) (0x9c + 0x4 * (level)) + enum freq_policy { FLOOR, CEIL, @@ -929,3 +938,218 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw) .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent, }; EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); + +/* Common APIs to be used for DFS based RCGR */ +static unsigned long clk_rcg2_calculate_freq(struct clk_hw *hw, + int level, struct freq_tbl *f) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct clk_hw *p; + unsigned long prate = 0; + u32 val, mask, cfg, m_off, n_off, offset, mode; + int i, ret, num_parents; + + offset = SE_PERF_DFSR(level); + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg); + if (ret) + return ret; + + mask = BIT(rcg->hid_width) - 1; + f->pre_div = cfg & mask ? (cfg & mask) : 1; + + mode = cfg & CFG_MODE_MASK; + mode >>= CFG_MODE_SHIFT; + + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + num_parents = clk_hw_get_num_parents(hw); + for (i = 0; i < num_parents; i++) { + if (cfg == rcg->parent_map[i].cfg) { + f->src = rcg->parent_map[i].src; + p = clk_hw_get_parent_by_index(&rcg->clkr.hw, i); + prate = clk_hw_get_rate(p); + } + } + + if (mode) { + /* Calculate M & N values */ + m_off = SE_PERF_M_DFSR(level); + n_off = SE_PERF_N_DFSR(level); + + mask = BIT(rcg->mnd_width) - 1; + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + m_off, + &val); + if (ret) { + pr_err("Failed to read M offset register\n"); + return ret; + } + val &= mask; + f->m = val; + + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + n_off, + &val); + if (ret) { + pr_err("Failed to read N offset register\n"); + return ret; + } + /* val ~(N-M) */ + val = ~val; + val &= mask; + val += f->m; + f->n = val; + } + + return calc_rate(prate, f->m, f->n, mode, f->pre_div); +} + +static int clk_rcg2_dfs_populate_freq_table(struct clk_rcg2 *rcg) +{ + struct freq_tbl *freq_tbl; + unsigned long calc_freq; + int i; + + freq_tbl = kcalloc(MAX_PERF_LEVEL, sizeof(*freq_tbl), + GFP_KERNEL); + if (!freq_tbl) +
[PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
[v4] * Add recalc_clk_ops to calculate the clock frequency reading the current perf state, also add CLK_GET_RATE_NOCACHE flag. * Cleanup 'goto' during mode check in 'clk_rcg2_calculate_freq'. * cleanup return from function 'com_cc_register_rcg_dfs'. [v3] * Rename clk_rcg2_calculate_m_and_n with clk_rcg2_calculate_freq, as this function would now calculate the frequency. * Rename dfs_freq_tbl to freq_tbl. * Remove the logic to remove duplicate frequencies. * Remove recalc_rate & set_rate clock ops. * clk_rcg2_dfs_ops clock ops is static. * Override the clock ops only if DFS mode is enabled. * qcom_cc_register_rcg_dfs uses regmap instead of device. * Few cleanups : Remove DFS probing after registering clocks. sizeof(*init), sizeof(*freq_tbl). [v2] * Move the dfs register function 'qcom_cc_register_rcg_dfs' to clk-rcg2.c instead of common.c * At boot read the DFS enable register and override the clk_ops to be used for dfs or non-dfs RCGs. * Remove flag 'dfs_enabled'. * Remove functions 'clk_rcg2_dfs_determine_rate_lazy' * Remove 'struct dfs_table *dfs_entry' * Remove '_freq_tbl_determine_dfs_rate' * Combine the function 'clk_index_pre_div_and_mode' and 'calculate_m_and_n' to a single function and named it 'clk_rcg2_calculate_m_and_n'. * Remove taking M/N/PERF offsets as function arguments. * Add clocks in gcc-sdm845.c the DFS clock array to register. [v1] * Update SPDX for files. * Add new clk_ops for DFS mode which would be used if dfs is enabled, else fall back to the clk_rcg2_shared_ops. * Use kcalloc in place kzalloc. * Fixed the return type for 'clk_parent_index_pre_div_and_mode' which is now renamed to 'clk_index_pre_div_and_mode'. * Removed return of -EPERM from 'clk_rcg2_set_rate' and new dfs clk_ops is introduced. * Pass frequency table entry structure to function calculate_m_and_n. * Remove desc from qcom_cc_register_rcg_dfs and instead pass array of clk_rcg2. * Add a dfs_enable flag to identify if dfs mode is enabled. In the cases where a RCG requires a Dynamic Frequency switch support requires to register which would at runtime read the clock perf level registers to identify the frequencies supported and update the frequency table accordingly. Taniya Das (2): clk: qcom: Add support for RCG to register for DFS clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845 drivers/clk/qcom/clk-rcg.h| 2 + drivers/clk/qcom/clk-rcg2.c | 224 ++ drivers/clk/qcom/gcc-sdm845.c | 25 + 3 files changed, 251 insertions(+) -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Re: [PATCH] clk: qcom: Add Global Clock controller (GCC) driver for SDM660
Hello Craig, Could you please correct the authorship and also provide the reference to code where this is picked from? On 8/11/2018 1:51 AM, Craig Tatlor wrote: Add support for the global clock controller found on SDM660 based devices. This should allow most non-multimedia device drivers to probe and control their clocks. Based on CAF implementation. Signed-off-by: Craig Tatlor --- .../devicetree/bindings/clock/qcom,gcc.txt|1 + drivers/clk/qcom/Kconfig |9 + drivers/clk/qcom/Makefile |1 + drivers/clk/qcom/gcc-sdm660.c | 2479 + include/dt-bindings/clock/qcom,gcc-sdm660.h | 159 ++ 5 files changed, 2649 insertions(+) create mode 100644 drivers/clk/qcom/gcc-sdm660.c create mode 100644 include/dt-bindings/clock/qcom,gcc-sdm660.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 664ea1fd6c76..e498ad2e8db8 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -19,6 +19,7 @@ Required properties : "qcom,gcc-msm8996" "qcom,gcc-msm8998" "qcom,gcc-mdm9615" + "qcom,gcc-sdm660" "qcom,gcc-sdm845" - reg : shall contain base register location and length diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 9c3480dcc38a..c4bda6d24c1f 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -226,6 +226,15 @@ config MSM_GCC_8998 Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, UFS, SD/eMMC, PCIe, etc. +config SDM_GCC_660 + tristate "SDM660 Global Clock Controller" + select QCOM_GDSC + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on SDM660 devices. + Say Y if you want to use peripheral devices such as UART, SPI, + i2C, USB, UFS, SDDC, PCIe, etc. + config SDM_GCC_845 tristate "SDM845 Global Clock Controller" select QCOM_GDSC diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 762c01137c2f..6e37d30d7c02 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o +obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c new file mode 100644 index ..bdb445aa4baa --- /dev/null +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -0,0 +1,2479 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, Craig Tatlor. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-alpha-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" +#include "gdsc.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +enum { + P_XO, + P_SLEEP_CLK, + P_GPLL0, + P_GPLL1, + P_GPLL4, + P_GPLL0_EARLY_DIV, + P_GPLL1_EARLY_DIV, +}; + +static const struct parent_map gcc_parent_map_xo_gpll0_gpll0_early_div[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL0_EARLY_DIV, 6 }, +}; + +static const char * const gcc_parent_names_xo_gpll0_gpll0_early_div[] = { + "xo", + "gpll0", + "gpll0_early_div", +}; + +static const struct parent_map gcc_parent_map_xo_gpll0[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, +}; + +static const char * const gcc_parent_names_xo_gpll0[] = { + "xo", + "gpll0", +}; + +static const struct parent_map gcc_parent_map_xo_gpll0_sleep_clk_gpll0_early_div[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GPLL0_EARLY_DIV, 6 }, +}; + +static const char * const gcc_parent_names_xo_gpll0_sleep_clk_gpll0_early_div[] = { + "xo", + "gpll0", + "sleep_clk", + "gpll0_early_div", +}; + +static const struct parent_map gcc_parent_map_xo_sleep_clk[] = { + { P_XO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const char * const gcc_parent_names_xo_sleep_clk[] = { + "xo", + "sleep_clk", +}; + +static const struct parent_map gcc_parent_map_xo_gpll4[] = { + { P_XO, 0 }, + { P_GPLL4, 5 }, +}; + +static const char * const gcc_parent_names_xo_gpll4[] = { + "xo", + "gpll4", +}; + +static const struct parent_map gcc_parent_map
Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
Hello Stephen, Thanks for the changes, I have tested the changes and would require the change mentioned below for this to work. On 8/18/2018 11:31 PM, Taniya Das wrote: Hello Stephen, I will test these changes and get back. On 8/18/2018 7:42 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-08-10 18:53:54) [v4] * Add recalc_clk_ops to calculate the clock frequency reading the current perf state, also add CLK_GET_RATE_NOCACHE flag. * Cleanup 'goto' during mode check in 'clk_rcg2_calculate_freq'. * cleanup return from function 'com_cc_register_rcg_dfs'. I want to squash this in. I have only compile tested it. Let me know what you think. 8<--- diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index e6300e05d5df..e5eca8a1abe4 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -163,6 +163,15 @@ extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_rcg2_shared_ops; +struct clk_rcg_dfs_data { + struct clk_rcg2 *rcg; + struct clk_init_data *init; +}; + +#define DEFINE_RCG_DFS(r) \ + { .rcg = &r##_src, .init = &r##_init } + extern int qcom_cc_register_rcg_dfs(struct regmap *regmap, - struct clk_rcg2 **rcgs, int num_clks); + const struct clk_rcg_dfs_data *rcgs, + size_t len); #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 55a5b58cbb15..bbe2a1916296 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1051,48 +1051,24 @@ static unsigned long clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); - u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, level; - int num_parents, i; - unsigned long prate; - - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + - SE_CMD_DFSR_OFFSET, &cfg); - level = (GENMASK(4, 1) & cfg) >> 1; - - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + - SE_PERF_DFSR(level), &cfg); - if (rcg->mnd_width) { - mask = BIT(rcg->mnd_width) - 1; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + - SE_PERF_M_DFSR(level), &m); - m &= mask; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + - SE_PERF_N_DFSR(level), &n); - n = ~n; - n &= mask; - n += m; - mode = cfg & CFG_MODE_MASK; - mode >>= CFG_MODE_SHIFT; - } + int ret; + u32 level; - mask = BIT(rcg->hid_width) - 1; - hid_div = cfg >> CFG_SRC_DIV_SHIFT; - hid_div &= mask; - cfg &= CFG_SRC_SEL_MASK; - cfg >>= CFG_SRC_SEL_SHIFT; + regmap_read(rcg->clkr.regmap, + rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level); + level &= GENMASK(4, 1); + level >>= 1; - num_parents = clk_hw_get_num_parents(hw); - for (i = 0; i < num_parents; i++) { - if (cfg == rcg->parent_map[i].cfg) { - prate = clk_hw_get_rate( - clk_hw_get_parent_by_index(&rcg->clkr.hw, i)); - if (parent_rate != prate) - parent_rate = prate; + if (!rcg->freq_tbl) { + ret = clk_rcg2_dfs_populate_freq_table(rcg); This function would retrieve the parent_rate and if the parent_rate is not ready then it would fail to boot up. So we have to make sure the parents are registered before these RCGs. That also was one reason for me to not populate the frequency table at recalc. We would need this patch to make this work. /* GCC clock registers */ -#define GCC_AGGRE_NOC_PCIE_TBU_CLK 0 -#define GCC_AGGRE_UFS_CARD_AXI_CLK 1 -#define GCC_AGGRE_UFS_PHY_AXI_CLK 2 -#define GCC_AGGRE_USB3_PRIM_AXI_CLK3 +#define GPLL0 0 +#define GPLL0_OUT_EVEN 1 +#define GPLL0_OUT_MAIN 2 +#define GPLL4 3 #define GCC_AGGRE_USB3_SEC_AXI_CLK 4 #define GCC_BOOT_ROM_AHB_CLK 5 #define GCC_CAMERA_AHB_CLK 6 @@ -172,9 +172,9 @@ #define GCC_VIDEO_AHB_CLK 162 #define GCC_VIDEO_AXI_CLK 163 #define GCC_VIDEO_XO_CLK 164 -#define GPLL0 165 -#define GPLL0_OUT_EVEN 166 -#define GPLL0_OUT_MAIN 167 +#define GCC_AGGRE_NOC_PCIE_TBU_CLK
Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
On 8/21/2018 9:00 PM, Stephen Boyd wrote: Quoting Taniya Das (2018-08-21 04:36:20) On 8/18/2018 11:31 PM, Taniya Das wrote: Hello Stephen, I will test these changes and get back. On 8/18/2018 7:42 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-08-10 18:53:54) [v4] * Add recalc_clk_ops to calculate the clock frequency reading the current perf state, also add CLK_GET_RATE_NOCACHE flag. * Cleanup 'goto' during mode check in 'clk_rcg2_calculate_freq'. * cleanup return from function 'com_cc_register_rcg_dfs'. I want to squash this in. I have only compile tested it. Let me know what you think. 8<--- diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index e6300e05d5df..e5eca8a1abe4 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -163,6 +163,15 @@ extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_rcg2_shared_ops; +struct clk_rcg_dfs_data { + struct clk_rcg2 *rcg; + struct clk_init_data *init; +}; + +#define DEFINE_RCG_DFS(r) \ + { .rcg = &r##_src, .init = &r##_init } + extern int qcom_cc_register_rcg_dfs(struct regmap *regmap, - struct clk_rcg2 **rcgs, int num_clks); + const struct clk_rcg_dfs_data *rcgs, + size_t len); #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 55a5b58cbb15..bbe2a1916296 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1051,48 +1051,24 @@ static unsigned long clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); - u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, level; - int num_parents, i; - unsigned long prate; - - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + - SE_CMD_DFSR_OFFSET, &cfg); - level = (GENMASK(4, 1) & cfg) >> 1; - - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + - SE_PERF_DFSR(level), &cfg); - if (rcg->mnd_width) { - mask = BIT(rcg->mnd_width) - 1; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + - SE_PERF_M_DFSR(level), &m); - m &= mask; - regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + - SE_PERF_N_DFSR(level), &n); - n = ~n; - n &= mask; - n += m; - mode = cfg & CFG_MODE_MASK; - mode >>= CFG_MODE_SHIFT; - } + int ret; + u32 level; - mask = BIT(rcg->hid_width) - 1; - hid_div = cfg >> CFG_SRC_DIV_SHIFT; - hid_div &= mask; - cfg &= CFG_SRC_SEL_MASK; - cfg >>= CFG_SRC_SEL_SHIFT; + regmap_read(rcg->clkr.regmap, + rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level); + level &= GENMASK(4, 1); + level >>= 1; - num_parents = clk_hw_get_num_parents(hw); - for (i = 0; i < num_parents; i++) { - if (cfg == rcg->parent_map[i].cfg) { - prate = clk_hw_get_rate( - clk_hw_get_parent_by_index(&rcg->clkr.hw, i)); - if (parent_rate != prate) - parent_rate = prate; + if (!rcg->freq_tbl) { + ret = clk_rcg2_dfs_populate_freq_table(rcg); This function would retrieve the parent_rate and if the parent_rate is not ready then it would fail to boot up. So we have to make sure the parents are registered before these RCGs. That also was one reason for me to not populate the frequency table at recalc. We would need this patch to make this work. H. Ok. That won't work then. recalc_rate() better not try to populate the frequency table then or it will not work. So I suppose it needs to fallback to reading the registers and assuming the parent_rate coming in is the actual frequency of it's parent until the frequency table pointer is non-NULL. Would that work? Yes that would work. BTW, does DFS switch parents without software knowing about it? DFS would not switch until a HW request is sent, but SW would be unware of the switch except the current_perf_state being updated with the requested level. What happens in that case? Does the QUP driver make sure that the new parent of this RCG is properly enabled so that it can switch to it when needed? I am not sure if they poll for any of their QUP HW state to make sure the switch is complete. I'm still trying to understand this whole design. Who takes care of the voltage requirements in this case? The QUP driver as well? When the QUP driver requires to switch to new performance level, the first request would be to set_rate()(QUP driver would get the list of supported frequencies using the clk_round_rate()) which in QCOM clock driver would take care of setting the required voltage for the new parent switch. Then the QUP driver would req
Re: [PATCH v5] clk: qcom: Add display clock controller driver for SDM845
On 7/27/2018 3:35 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-07-23 03:54:35) Add support for the display clock controller found on SDM845 based devices. This would allow display drivers to probe and control their clocks. Signed-off-by: Taniya Das --- This is fine to merge as long as you're ok with removing the no rate cache flag. I can do that myself so you don't have to resend. Thanks, please go ahead and remove the flags, in case the display drivers would require the flags for any proper use case then we could think on re-introducing them. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [RFC PATCH 2/2] clk: qcom: Add qspi (Quad SPI) clocks for sdm845
Hi Doug, Please find my comments inline. On 7/18/2018 11:34 PM, Douglas Anderson wrote: Add both the interface and core clock. Signed-off-by: Douglas Anderson --- drivers/clk/qcom/gcc-sdm845.c | 73 +++ 1 file changed, 73 insertions(+) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 0f694ed4238a..2ee96f9bc217 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -162,6 +162,20 @@ static const char * const gcc_parent_names_10[] = { "core_bi_pll_test_se", }; +static const struct parent_map gcc_parent_map_9[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_SLEEP_CLK, 7 }, SRC 7 has 'core_bi_pll_test_se' and not 'sleep_clk'. Please use the 'gcc_parent_map_0' +}; + +static const char * const gcc_parent_names_9[] = { + "bi_tcxo", + "gpll0", + "gpll0_out_even", + "core_pi_sleep_clk", +}; + static struct clk_alpha_pll gpll0 = { .offset = 0x0, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], @@ -358,6 +372,31 @@ static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = { }, }; +static const struct freq_tbl ftbl_gcc_qspi_core_clk_src[] = { + F(1920, P_BI_TCXO, 1, 0, 0), + F(5000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(7500, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(1, P_GPLL0_OUT_EVEN, 3, 0, 0), Is SW planning to use this frequency? + F(15000, P_GPLL0_OUT_EVEN, 2, 0, 0), F(15000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(3, P_GPLL0_OUT_EVEN, 1, 0, 0), F(3, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(4, P_GPLL0_OUT_MAIN, 1.5, 0, 0), Please remove this, the Max supported frequency is 300MHz. + { } +}; + +static struct clk_rcg2 gcc_qspi_core_clk_src = { + .cmd_rcgr = 0x4b008, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_qspi_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_core_clk_src", + .parent_names = gcc_parent_names_9, + .num_parents = 4, + .ops = &clk_rcg2_floor_ops, Could we use the rcg2_ops instead? + }, +}; + static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { F(960, P_BI_TCXO, 2, 0, 0), F(1920, P_BI_TCXO, 1, 0, 0), @@ -1935,6 +1974,37 @@ static struct clk_branch gcc_qmip_video_ahb_clk = { }, }; +static struct clk_branch gcc_qspi_cnoc_periph_ahb_clk = { + .halt_reg = 0x4b000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_cnoc_periph_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qspi_core_clk = { + .halt_reg = 0x4b004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4b004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_core_clk", + .parent_names = (const char *[]){ + "gcc_qspi_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_qupv3_wrap0_s0_clk = { .halt_reg = 0x17030, .halt_check = BRANCH_HALT_VOTED, @@ -3383,6 +3453,9 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GPLL4] = &gpll4.clkr, [GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr, [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, + [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr, + [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr, + [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [RFC PATCH 2/2] clk: qcom: Add qspi (Quad SPI) clocks for sdm845
On 7/19/2018 11:25 PM, Doug Anderson wrote: Hi, On Thu, Jul 19, 2018 at 4:04 AM, Taniya Das wrote: Hi Doug, Please find my comments inline. On 7/18/2018 11:34 PM, Douglas Anderson wrote: Add both the interface and core clock. Signed-off-by: Douglas Anderson --- drivers/clk/qcom/gcc-sdm845.c | 73 +++ 1 file changed, 73 insertions(+) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 0f694ed4238a..2ee96f9bc217 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -162,6 +162,20 @@ static const char * const gcc_parent_names_10[] = { "core_bi_pll_test_se", }; +static const struct parent_map gcc_parent_map_9[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_SLEEP_CLK, 7 }, SRC 7 has 'core_bi_pll_test_se' and not 'sleep_clk'. Please use the 'gcc_parent_map_0' Are you sure? I'm looking at a doc showing the bitfields of GCC_QSPI_CORE_CFG_RCGR. It says: 0x0: bi_tcxo. 0x1: gpll0_out_main. 0x6: gpll0_out_even. 0x7: sleep_clk. This contrasts with other clocks using 'gcc_parent_map_0' (for instance "gcc_qupv3_wrap0_s0_clk_src") where 0x7 is simply not listed in my doc. ...so either my doc is wrong or yours is. Any way to resolve that? I am not sure of the document you are referring, but the connectivity details I have shared are from the design side and they are ones which we have to follow. +}; + +static const char * const gcc_parent_names_9[] = { + "bi_tcxo", + "gpll0", + "gpll0_out_even", + "core_pi_sleep_clk", +}; + static struct clk_alpha_pll gpll0 = { .offset = 0x0, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], @@ -358,6 +372,31 @@ static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = { }, }; +static const struct freq_tbl ftbl_gcc_qspi_core_clk_src[] = { + F(1920, P_BI_TCXO, 1, 0, 0), + F(5000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(7500, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(1, P_GPLL0_OUT_EVEN, 3, 0, 0), Is SW planning to use this frequency? At the moment I actually am using it. I haven't done signal analysis, but in quick testing I couldn't properly read the SPI at faster than a 25 MHz SPI bus which translates to 100 MHz here. Interestingly, it seems like folks in your boot team came to the same conclusion since I see them setting this bus to 100 MHz at <https://review.coreboot.org/#/c/coreboot/+/25392/25/src/soc/qualcomm/sdm845/bootblock.c> too. + F(15000, P_GPLL0_OUT_EVEN, 2, 0, 0), F(15000, P_GPLL0_OUT_MAIN, 4, 0, 0), Sure. For my edification, is there a reason to use main vs. even? The frequencies to be generated are also as per design data. These source usage depends on timing closure for certain max frequencies. + F(3, P_GPLL0_OUT_EVEN, 1, 0, 0), F(3, P_GPLL0_OUT_MAIN, 2, 0, 0), No problem. + F(4, P_GPLL0_OUT_MAIN, 1.5, 0, 0), No problem. Please remove this, the Max supported frequency is 300MHz. + { } +}; + +static struct clk_rcg2 gcc_qspi_core_clk_src = { + .cmd_rcgr = 0x4b008, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_qspi_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_core_clk_src", + .parent_names = gcc_parent_names_9, + .num_parents = 4, + .ops = &clk_rcg2_floor_ops, Could we use the rcg2_ops instead? I'd rather not. Any reason why you think that'd be a good idea? Specifically imagine that we have a SPI flash chip that's rated to run at a max of 20 MHz. In the device tree we'd ideally want to specify: spi-max-frequency = <2000>; It appears that we need to run the SPI core as 4 times the rate of the SPI bus, so we'd try to set this clock to 80 MHz. If we round up we'll end up at 100 MHz or 150 MHz for the SPI core and have a SPI bus rate of 25 MHz or 37.5 MHz. That would violate the whole idea of "spi-max-frequency". It's much better to round down to 75 MHz. In general I've always seen that for safety it's always better the round clocks down and round voltage up, so I was actually confused by the fact that most of the clocks in this file used rcg2_ops instead of clk_rcg2_floor_ops... I'd be curious if we should we change more of them to clk_rcg2_floor_ops. As a random example I'll take "gcc_sdcc2_apps_clk_src". If someone happened to have a full sized SD slot and put an MMC card in then you'd be in trouble. Why? For MMC a valid rate to request is 5200. When the SD card core r
[RFC PATCH 1/4] clk: qcom: Add support to request power domain state
There could be single power domain or multiple power domains associated with a clock controller. Add powerdomain_class support which would help vote/unvote for any power domain performance state for a clock frequency to the genpd framework. A clock frequency request from a consumer would look for the corresponding performance corner and thus would aggregate and request the desired performance state to genpd. Signed-off-by: Taniya Das --- drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-pd.c | 193 ++ drivers/clk/qcom/clk-pd.h | 55 + 3 files changed, 249 insertions(+) create mode 100644 drivers/clk/qcom/clk-pd.c create mode 100644 drivers/clk/qcom/clk-pd.h diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 599ab91..336d4da 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -12,6 +12,7 @@ clk-qcom-y += clk-regmap-divider.o clk-qcom-y += clk-regmap-mux.o clk-qcom-y += clk-regmap-mux-div.o clk-qcom-y += reset.o +clk-qcom-y += clk-pd.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o # Keep alphabetically sorted by config diff --git a/drivers/clk/qcom/clk-pd.c b/drivers/clk/qcom/clk-pd.c new file mode 100644 index 000..d1f9df3 --- /dev/null +++ b/drivers/clk/qcom/clk-pd.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk-pd.h" +#include "clk-regmap.h" + +struct clk_powerdomain { + struct list_head list; + struct clk_powerdomain_class *pd; +}; + +static LIST_HEAD(clk_pd_list); + +/* Find the corner required for a given clock rate */ +static int find_rate_to_corner(struct clk_regmap *rclk, unsigned long rate) +{ + int corner; + + for (corner = 0; corner < rclk->pd->num_corners; corner++) + if (rate <= rclk->rate_max[corner]) + break; + + if (corner == rclk->pd->num_corners) { + pr_debug("Rate %lu for %s is > than highest Fmax\n", rate, +rclk->hw.init->name); + return -EINVAL; + } + + return corner; +} + +static int pd_update_corner_state(struct clk_powerdomain_class *pd) +{ + int corner, ret, *state = pd->corner, i; + int cur_corner = pd->cur_corner, max_corner = pd->num_corners - 1; + + /* Aggregate the corner */ + for (corner = max_corner; corner > 0; corner--) { + if (pd->corner_votes[corner]) + break; + } + + if (corner == cur_corner) + return 0; + + pr_debug("Set performance state to genpd(%s) for state %d, cur_corner %d, num_corner %d\n", +pd->pd_name, state[corner], cur_corner, pd->num_corners); + + for (i = 0; i < pd->num_pd; i++) { + ret = dev_pm_genpd_set_performance_state(pd->powerdomain_dev[i], +state[corner]); + if (ret) + return ret; + + if (cur_corner == 0 || cur_corner == pd->num_corners) { + pd->links[i] = device_link_add(pd->dev, + pd->powerdomain_dev[i], + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!pd->links[i]) + pr_err("Links for %d not created\n", i); + } + + if (corner == 0) + device_link_del(pd->links[i]); + } + + pd->cur_corner = corner; + + return 0; +} + +/* call from prepare & set rate */ +int clk_power_domain_vote_rate(struct clk_regmap *rclk, + unsigned long rate) +{ + int corner; + + if (!rclk->pd) + return 0; + + corner = find_rate_to_corner(rclk, rate); + if (corner < 0) + return corner; + + mutex_lock(&rclk->pd->lock); + + rclk->pd->corner_votes[corner]++; + + /* update the corner to power domain */ + if (pd_update_corner_state(rclk->pd) < 0) + rclk->pd->corner_votes[corner]--; + + pr_debug("pd(%s) prepare corner_votes_count %d, corner %d\n", +rclk->pd->pd_name, rclk->pd->corner_votes[corner], +corner); + + mutex_unlock(&rclk->pd->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(clk_power_domain_vote_rate); + +/* call from unprepare & set rate */ +void clk_power_domain_unvote_rate(struct clk_regmap *rclk, + unsigned long r
[RFC PATCH 2/4] clk: qcom: Initialize the power domain class for each clock
The power domain class is being initialized for clocks which has an associated power domains before registering the clocks with the clock framework. Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-regmap.h | 5 + drivers/clk/qcom/common.c | 17 +++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/clk/qcom/clk-regmap.h b/drivers/clk/qcom/clk-regmap.h index 90d95cd..6265d91 100644 --- a/drivers/clk/qcom/clk-regmap.h +++ b/drivers/clk/qcom/clk-regmap.h @@ -17,22 +17,27 @@ #include struct regmap; +struct clk_powerdomain_class; /** * struct clk_regmap - regmap supporting clock * @hw:handle between common and hardware-specific interfaces * @regmap:regmap to use for regmap helpers and/or by providers + * @pd:power domain scaling requirement class * @enable_reg: register when using regmap enable/disable ops * @enable_mask: mask when using regmap enable/disable ops * @enable_is_inverted: flag to indicate set enable_mask bits to disable * when using clock_enable_regmap and friends APIs. + * @rate_max: maximum clock rate in Hz supported at each power domain. */ struct clk_regmap { struct clk_hw hw; struct regmap *regmap; + struct clk_powerdomain_class *pd; unsigned int enable_reg; unsigned int enable_mask; bool enable_is_inverted; + unsigned long *rate_max; }; #define to_clk_regmap(_hw) container_of(_hw, struct clk_regmap, hw) diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 39ce64c..b0684bf 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved. */ #include @@ -20,6 +12,7 @@ #include #include "common.h" +#include "clk-pd.h" #include "clk-rcg.h" #include "clk-regmap.h" #include "reset.h" @@ -263,6 +256,10 @@ int qcom_cc_really_probe(struct platform_device *pdev, if (!rclks[i]) continue; + ret = clk_power_domain_class_init(dev, rclks[i]->pd); + if (ret) + return ret; + ret = devm_clk_register_regmap(dev, rclks[i]); if (ret) return ret; -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[RFC PATCH 0/4] clk: qcom: Add support to vote to genpd
A clock controller could be connected to single or multiple power domains. Add support for powerdomain_class which would help associate these power domains to the RCGs and PLLs in the clock controller. Map the domain and the corresponding frequencies to the clock(RCG/PLL). The clock frequency request from a consumer would be mapped to the corresponding performance corner, aggregated at the clock driver and would be vote/unvoted to the genpd framework for the desired performance state. This series add an example of power domain class for sdm845 RCG/PLLs and the corresponding frequency mappings. This depends on power domain drivers of SDM845 https://lkml.org/lkml/2018/6/27/7. Taniya Das (4): clk: qcom: Add support to request power domain state clk: qcom: Initialize the power domain class for each clock clk: qcom: Add prepare/unprepare clock ops for PLL/RCG clk: qcom: sdm845: Add Power Domain to RCGs and PLL arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 + drivers/clk/qcom/Makefile| 1 + drivers/clk/qcom/clk-alpha-pll.c | 52 -- drivers/clk/qcom/clk-pd.c| 193 +++ drivers/clk/qcom/clk-pd.h| 55 ++ drivers/clk/qcom/clk-rcg2.c | 61 +-- drivers/clk/qcom/clk-regmap.h| 5 + drivers/clk/qcom/common.c| 17 ++- drivers/clk/qcom/gcc-sdm845.c| 83 --- 9 files changed, 427 insertions(+), 42 deletions(-) create mode 100644 drivers/clk/qcom/clk-pd.c create mode 100644 drivers/clk/qcom/clk-pd.h -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[RFC PATCH 3/4] clk: qcom: Add prepare/unprepare clock ops for PLL/RCG
To put across power domain votes associated with a PLL or RCG, add the prepare/unprepare clock ops which would map the corresponding performance state corners for a clock frequency when the clk_prepare/clk_unprepare is being invoked. Also update the set_rate clock ops to send across the performance state to genpd framework when a new frequency is being requested. Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-alpha-pll.c | 52 +++--- drivers/clk/qcom/clk-rcg2.c | 61 +++- 2 files changed, 96 insertions(+), 17 deletions(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 3c49a60..c03b6e4 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include @@ -18,6 +10,7 @@ #include #include "clk-alpha-pll.h" +#include "clk-pd.h" #include "common.h" #define PLL_MODE(p)((p)->offset + 0x0) @@ -522,7 +515,9 @@ static int __clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); const struct pll_vco *vco; u32 l, alpha_width = pll_alpha_width(pll); + unsigned long old_rate = clk_hw_get_rate(hw); u64 a; + int ret; rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); vco = alpha_pll_find_vco(pll, rate); @@ -531,6 +526,15 @@ static int __clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; } + if (clk_hw_is_prepared(hw)) { + /* Enforce power domain requirement for new frequency */ + ret = clk_power_domain_vote_rate(&pll->clkr, rate); + if (ret) { + pr_err("Failed to vote/set new rate %lu\n", rate); + return ret; + } + } + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); if (alpha_width > ALPHA_BITWIDTH) @@ -550,7 +554,15 @@ static int __clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), PLL_ALPHA_EN, PLL_ALPHA_EN); - return clk_alpha_pll_update_latch(pll, is_enabled); + ret = clk_alpha_pll_update_latch(pll, is_enabled); + if (ret) + old_rate = rate; + + if (clk_hw_is_prepared(hw)) + /* Release the power domain requirement for old frequency */ + clk_power_domain_unvote_rate(&pll->clkr, old_rate); + + return ret; } static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -1017,7 +1029,25 @@ static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate, return __clk_alpha_pll_update_latch(pll); } +static int clk_alpha_pll_prepare(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + unsigned long rate = clk_hw_get_rate(hw); + + return clk_power_domain_vote_rate(&pll->clkr, rate); +} + +static void clk_alpha_pll_unprepare(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + unsigned long rate = clk_hw_get_rate(hw); + + clk_power_domain_unvote_rate(&pll->clkr, rate); +} + const struct clk_ops clk_alpha_pll_fabia_ops = { + .prepare = clk_alpha_pll_prepare, + .unprepare = clk_alpha_pll_unprepare, .enable = alpha_pll_fabia_enable, .disable = alpha_pll_fabia_disable, .is_enabled = clk_alpha_pll_is_enabled, @@ -1028,6 +1058,8 @@ static int alpha_pll_fabia_set_rate(struct clk_hw *hw, unsigned long rate, EXPORT_SYMBOL_GPL(clk_alpha_pll_fabia_ops); const struct clk_ops clk_alpha_pll_fixed_fabia_ops = { + .prepare = clk_alpha_pll_prepare, + .unprepare = clk_alpha_pll_unprepare, .enable = alpha_pll_fabia_enable, .disable = alpha_pll_fabia_disable, .is_enabled = clk_alpha_pll_is_enabled, diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 52208d4..dc17dbf 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -15,6 +15,7 @@ #include +#include "clk-pd.h" #include "clk-rcg.h" #include "common.h" @@ -247,26 +248,46 @@ static
[RFC PATCH 4/4] clk: qcom: sdm845: Add Power Domain to RCGs and PLL
Test code for GCC Power Domain Voting for root clocks/plls. Signed-off-by: Taniya Das --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 + drivers/clk/qcom/gcc-sdm845.c| 83 +--- drivers/clk/qcom/vdd-level.h | 31 ++ 3 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 drivers/clk/qcom/vdd-level.h diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 00722b5..742f72a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -247,6 +247,8 @@ #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; + power-domains = <&rpmhpd SDM845_CX>, + <&rpmhpd SDM845_CX_AO>; }; qupv3_id_0: geniqup@8c { diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 0f694ed..60225c1 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -24,6 +24,11 @@ #include "clk-alpha-pll.h" #include "gdsc.h" #include "reset.h" +#include "clk-pd.h" +#include "vdd-level.h" + +#include +#include #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } @@ -162,12 +167,22 @@ enum { "core_bi_pll_test_se", }; +static CLK_POWERDOMAIN_INIT(vdd_cx, VDD_NUM, 1, vdd_corner); +static CLK_POWERDOMAIN_INIT(vdd_cx_ao, VDD_NUM, 1, vdd_corner); + static struct clk_alpha_pll gpll0 = { .offset = 0x0, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .enable_reg = 0x52000, .enable_mask = BIT(0), + .pd = &vdd_cx, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 61500, + [VDD_LOW] = 106600, + [VDD_LOW_L1] = 16, + [VDD_NOMINAL] = 20, + }, .hw.init = &(struct clk_init_data){ .name = "gpll0", .parent_names = (const char *[]){ "bi_tcxo" }, @@ -183,6 +198,13 @@ enum { .clkr = { .enable_reg = 0x52000, .enable_mask = BIT(4), + .pd = &vdd_cx, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 61500, + [VDD_LOW] = 106600, + [VDD_LOW_L1] = 16, + [VDD_NOMINAL] = 20, + }, .hw.init = &(struct clk_init_data){ .name = "gpll4", .parent_names = (const char *[]){ "bi_tcxo" }, @@ -226,11 +248,20 @@ enum { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_cpuss_ahb_clk_src, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_cpuss_ahb_clk_src", - .parent_names = gcc_parent_names_7, - .num_parents = 4, - .ops = &clk_rcg2_ops, + .clkr = { + /* .pd = &vdd_cx_ao, Remove this for testing */ + .pd = &vdd_cx, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 1920, + [VDD_LOW] = 5000, + [VDD_NOMINAL] = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk_src", + .parent_names = gcc_parent_names_7, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, }, }; @@ -268,11 +299,20 @@ enum { .hid_width = 5, .parent_map = gcc_parent_map_1, .freq_tbl = ftbl_gcc_gp1_clk_src, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_gp1_clk_src", - .parent_names = gcc_parent_names_1, - .num_parents = 5, - .ops = &clk_rcg2_ops, + .clkr = { + .pd = &vdd_cx_ao, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 1920, + [VDD_LOWER] = 5000, + [VDD_LOW] = 1, + [VDD_NOMINAL] = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk_src", + .parent_names = gcc_parent_names_1, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, }, }; @@ -282,11 +322,20
[PATCH v4] Add display clock controller driver for SDM845
[v4] * Add comments for the RCGs/CBCRs using the CLK_GET_RATE_NOCACHE flag. [v3] * Move frequency table macro to common file, add the patch along to maintain dependency. [v2] * Removed unused header file includes. * Moved the frequency table macro to a common file [1]. * Move to pll config to probe. * Update SoC name in device tree binding and also update the Kconfig. Add support for the display clock controller found on SDM845 based devices. This would allow display drivers to probe and control their clocks. Taniya Das (1): clk: qcom: Add display clock controller driver for SDM845 drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile| 1 + drivers/clk/qcom/dispcc-sdm845.c | 686 +++ 3 files changed, 697 insertions(+) create mode 100644 drivers/clk/qcom/dispcc-sdm845.c -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v4] clk: qcom: Add display clock controller driver for SDM845
Add support for the display clock controller found on SDM845 based devices. This would allow display drivers to probe and control their clocks. Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile| 1 + drivers/clk/qcom/dispcc-sdm845.c | 686 +++ 3 files changed, 697 insertions(+) create mode 100644 drivers/clk/qcom/dispcc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 2b69cf2..0647686 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -254,6 +254,16 @@ config SDM_VIDEOCC_845 Say Y if you want to support video devices and functionality such as video encode and decode. +config SDM_DISPCC_845 + tristate "SDM845 Display Clock Controller" + select SDM_GCC_845 + depends on COMMON_CLK_QCOM + help + Support for the display clock controller on Qualcomm Technologies, Inc + SDM845 devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config SPMI_PMIC_CLKDIV tristate "SPMI PMIC clkdiv Support" depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 599ab91..21a4503 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o +obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c new file mode 100644 index 000..266b011 --- /dev/null +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -0,0 +1,686 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap-divider.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_DISP_CC_PLL0_OUT_MAIN, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, +}; + +static const struct parent_map disp_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_0[] = { + "bi_tcxo", + "dsi0_phy_pll_out_byteclk", + "dsi1_phy_pll_out_byteclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_2[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN_DIV, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_3[] = { + "bi_tcxo", + "disp_cc_pll0", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_4[] = { + "bi_tcxo", + "dsi0_phy_pll_out_dsiclk", + "dsi1_phy_pll_out_dsiclk", + "core_bi_pll_test_se", +}; + +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { +
[PATCH v5] Add display clock controller driver for SDM845
[v5] * Initialize pll config before assigining l/alpha values for pll configure. * Add module description. [v4] * Add comments for the RCGs/CBCRs using the CLK_GET_RATE_NOCACHE flag. [v3] * Move frequency table macro to common file, add the patch along to maintain dependency. [v2] * Removed unused header file includes. * Moved the frequency table macro to a common file [1]. * Move to pll config to probe. * Update SoC name in device tree binding and also update the Kconfig. Add support for the display clock controller found on SDM845 based devices. This would allow display drivers to probe and control their clocks. Taniya Das (1): clk: qcom: Add display clock controller driver for SDM845 drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile| 1 + drivers/clk/qcom/dispcc-sdm845.c | 687 +++ 3 files changed, 698 insertions(+) create mode 100644 drivers/clk/qcom/dispcc-sdm845.c -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v5] clk: qcom: Add display clock controller driver for SDM845
Add support for the display clock controller found on SDM845 based devices. This would allow display drivers to probe and control their clocks. Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 10 + drivers/clk/qcom/Makefile| 1 + drivers/clk/qcom/dispcc-sdm845.c | 687 +++ 3 files changed, 698 insertions(+) create mode 100644 drivers/clk/qcom/dispcc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 2b69cf2..0647686 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -254,6 +254,16 @@ config SDM_VIDEOCC_845 Say Y if you want to support video devices and functionality such as video encode and decode. +config SDM_DISPCC_845 + tristate "SDM845 Display Clock Controller" + select SDM_GCC_845 + depends on COMMON_CLK_QCOM + help + Support for the display clock controller on Qualcomm Technologies, Inc + SDM845 devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config SPMI_PMIC_CLKDIV tristate "SPMI PMIC clkdiv Support" depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 599ab91..21a4503 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o +obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c new file mode 100644 index 000..31850b6 --- /dev/null +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -0,0 +1,687 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap-divider.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_DISP_CC_PLL0_OUT_MAIN, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, +}; + +static const struct parent_map disp_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_0[] = { + "bi_tcxo", + "dsi0_phy_pll_out_byteclk", + "dsi1_phy_pll_out_byteclk", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_2[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN_DIV, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_3[] = { + "bi_tcxo", + "disp_cc_pll0", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map disp_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_4[] = { + "bi_tcxo", + "dsi0_phy_pll_out_dsiclk", + "dsi1_phy_pll_out_dsiclk", + "core_bi_pll_test_se", +}; + +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +/* Return the HW recalc rate for idle use case */ +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { +
Re: [PATCH v2 2/2] clk: qcom: Add qspi (Quad SPI) clocks for sdm845
On 7/24/2018 3:24 AM, Douglas Anderson wrote: Add both the interface and core clock. Signed-off-by: Douglas Anderson --- Changes in v2: - Only 19.2, 100, 150, and 300 MHz now. - All clocks come from MAIN rather than EVEN. - Use parent map 0 instead of new parent map 9. drivers/clk/qcom/gcc-sdm845.c | 63 +++ 1 file changed, 63 insertions(+) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 0f694ed4238a..5bca634e277a 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -162,6 +162,13 @@ static const char * const gcc_parent_names_10[] = { "core_bi_pll_test_se", }; +static const char * const gcc_parent_names_9[] = { + "bi_tcxo", + "gpll0", + "gpll0_out_even", + "core_pi_sleep_clk", +}; + Please remove this. static struct clk_alpha_pll gpll0 = { .offset = 0x0, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], @@ -358,6 +365,28 @@ static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = { }, }; +static const struct freq_tbl ftbl_gcc_qspi_core_clk_src[] = { + F(1920, P_BI_TCXO, 1, 0, 0), + F(1, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(15000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(3, P_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qspi_core_clk_src = { + .cmd_rcgr = 0x4b008, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qspi_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_core_clk_src", + .parent_names = gcc_parent_names_9, This would point to "gcc_parent_names_0". + .num_parents = 4, + .ops = &clk_rcg2_floor_ops, + }, +}; + static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { F(960, P_BI_TCXO, 2, 0, 0), F(1920, P_BI_TCXO, 1, 0, 0), @@ -1935,6 +1964,37 @@ static struct clk_branch gcc_qmip_video_ahb_clk = { }, }; +static struct clk_branch gcc_qspi_cnoc_periph_ahb_clk = { + .halt_reg = 0x4b000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_cnoc_periph_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qspi_core_clk = { + .halt_reg = 0x4b004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4b004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_qspi_core_clk", + .parent_names = (const char *[]){ + "gcc_qspi_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_qupv3_wrap0_s0_clk = { .halt_reg = 0x17030, .halt_check = BRANCH_HALT_VOTED, @@ -3383,6 +3443,9 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GPLL4] = &gpll4.clkr, [GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr, [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, + [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr, + [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr, + [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v7 0/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
[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 | 348 + 4 files changed, 532 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.
Re: [PATCH v6 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
Hello Viresh, Thanks for your review comments. On 7/18/2018 11:16 AM, Viresh Kumar wrote: On 18-07-18, 11:07, Taniya Das wrote: +static int qcom_cpu_resources_init(struct platform_device *pdev, + struct device_node *np, unsigned int cpu, + unsigned long xo_rate) +{ + struct cpufreq_qcom *c; + struct resource res; + struct device *dev = &pdev->dev; + const u16 *offsets; + cpumask_t cpus_related; + int ret, i, cpu_r; + void __iomem *base; + + cpumask_clear(&cpus_related); + + ret = qcom_get_related_cpus(np, &cpus_related); + if (ret) { + dev_err(dev, "%s failed to get related CPUs\n", np->name); + return ret; + } + + /* Related CPUs */ + cpu_r = cpumask_first(&cpus_related); + if (cpu != cpu_r) { + qcom_freq_domain_map[cpu] = qcom_freq_domain_map[cpu_r]; + return 0; + } + + c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL); + if (!c) + return -ENOMEM; + + offsets = of_device_get_match_data(&pdev->dev); + if (!offsets) + return -EINVAL; + + if (of_address_to_resource(np, 0, &res)) + return -ENOMEM; + + base = devm_ioremap_resource(dev, &res); + if (!base) + return -ENOMEM; + + for (i = REG_ENABLE; i < REG_ARRAY_SIZE; i++) + c->reg_bases[i] = base + offsets[i]; + + /* HW should be in enabled state to proceed */ + if (!(readl_relaxed(c->reg_bases[REG_ENABLE]) & 0x1)) { + dev_err(dev, "%s cpufreq hardware not enabled\n", np->name); + return -ENODEV; + } + + cpumask_copy(&c->related_cpus, &cpus_related); + + c->max_cores = cpumask_weight(&c->related_cpus); + if (!c->max_cores) + return -ENOENT; + + c->xo_rate = xo_rate; + + ret = qcom_cpufreq_hw_read_lut(pdev, c); + if (ret) { + dev_err(dev, "%s failed to read LUT\n", np->name); + return ret; + } + + qcom_freq_domain_map[cpu] = c; Set this for all related CPUs here and then the check at the top of this routine will be simply: if (qcom_freq_domain_map[cpu]) return 0; Please check the latest series, I have updated the code. + + return 0; +} + -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v7 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. Signed-off-by: Taniya Das --- .../bindings/cpufreq/cpufreq-qcom-hw.txt | 172 + 1 file changed, 172 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file mode 100644 index 000..22d4355 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt @@ -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: + Definition: must be "qcom,cpufreq-hw". + +- clocks + Usage: required + Value type: From common clock binding. + Definition: clock handle for XO clock. + +- clock-names + Usage: required + Value type: From common clock binding. + Definition: must be "xo". + +* Property qcom,freq-domain +Devices supporting freq-domain must set their "qcom,freq-domain" property with +phandle to a freq_domain_table in their DT node. + +* Frequency Domain Table Node + +This describes the frequency domain belonging to a device. +This node can have following properties: + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the HW bases. + +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 = <&freq_domain_table0>; + 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 = <&freq_domain_table0>; + 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 = <&freq_domain_table0>; + 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 = <&freq_domain_table0>; + 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 = <
[PATCH v7 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
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 Signed-off-by: Taniya Das --- drivers/cpufreq/Kconfig.arm | 11 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 348 ++ 3 files changed, 360 insertions(+) create mode 100644 drivers/cpufreq/qcom-cpufreq-hw.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 0cd8eb7..93a9d72 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -298,3 +298,14 @@ config ARM_PXA2xx_CPUFREQ This add the CPUFreq driver support for Intel PXA2xx SOCs. If in doubt, say N. + +config ARM_QCOM_CPUFREQ_HW + bool "QCOM CPUFreq HW driver" + depends on ARCH_QCOM + 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. diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index c1ffeab..ca48a1d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -85,6 +85,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)+= tegra124-cpufreq.o obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o ## diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c new file mode 100644 index 000..ea8f7d1 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#define INIT_RATE 3UL +#define LUT_MAX_ENTRIES40U +#define CORE_COUNT_VAL(val)(((val) & (GENMASK(18, 16))) >> 16) +#define LUT_ROW_SIZE 32 + +enum { + REG_ENABLE, + REG_LUT_TABLE, + REG_PERF_STATE, + + REG_ARRAY_SIZE, +}; + +struct cpufreq_qcom { + struct cpufreq_frequency_table *table; + struct device *dev; + void __iomem *reg_bases[REG_ARRAY_SIZE]; + cpumask_t related_cpus; + unsigned int max_cores; + unsigned long xo_rate; +}; + +static const u16 cpufreq_qcom_std_offsets[REG_ARRAY_SIZE] = { + [REG_ENABLE]= 0x0, + [REG_LUT_TABLE] = 0x110, + [REG_PERF_STATE]= 0x920, +}; + +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; + +static int +qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, +unsigned int index) +{ + struct cpufreq_qcom *c = policy->driver_data; + + writel_relaxed(index, c->reg_bases[REG_PERF_STATE]); + + return 0; +} + +static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) +{ + struct cpufreq_qcom *c; + struct cpufreq_policy *policy; + unsigned int index; + + policy = cpufreq_cpu_get_raw(cpu); + if (!policy) + return 0; + + c = policy->driver_data; + + index = readl_relaxed(c->reg_bases[REG_PERF_STATE]); + 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) +{ + struct cpufreq_qcom *c = policy->driver_data; + int index; + + index = policy->cached_resolved_idx; + if (index < 0) + return 0; + + writel_relaxed(index, c->reg_bases[REG_PERF_STATE]); + + return policy->freq_table[index].frequency; +} + +static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) +{ + struct cpufreq_qcom *c; + + c = qcom_freq_domain_map[policy->cpu]; + if (!c) { + pr_err("No scaling support for CPU%d\n", policy->cpu); + return -ENODEV; + } + + cpumask_copy(policy->cpus, &c->related_cpus); + + policy->fast_switch_possible = true; + policy->freq_table = c->table; + policy->driver_data = c; + + return 0; +} + +static struct freq_attr *qcom_cpufreq_hw_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + &cpufreq_freq_attr_scaling_boost_f
Re: [PATCH v3 3/3] clk: qcom: Add display clock controller driver for SDM845
++ Display driver team, On 7/9/2018 8:36 PM, Stephen Boyd wrote: Quoting Taniya Das (2018-07-09 02:34:07) On 7/9/2018 1:07 PM, Stephen Boyd wrote: Quoting Taniya Das (2018-07-09 00:07:21) On 7/9/2018 11:46 AM, Stephen Boyd wrote: > Why is the nocache flag needed? Applies to all clks in this file. > This flag is required for all RCGs whose PLLs are controlled outside the clock controller. The display code would require the recalculated rate always. Right. Why is the PLL controlled outside of the clock controller? The rate should propagate upward to the PLL from here, so who's going outside of that? The DSI0/1 PLL are not part of the display clock controller, but in the display subsystem which are managed by the DRM drivers. When DRM drivers query for the rate clock driver should always return the non cached rates. Why? Is the DSI PLL changing rate all the time, randomly, without going through the clk APIs to do so? Hmm, I am afraid I do not have an answer for this, but this was the requirement to always return the non cached rates from the clock driver. Ok. Who knows about this requirement? Can we add someone from the display driver to understand more? As per my discussions offline with the display teams, There is a use-case where the clock framework is unaware of the PLL VCO frequency change and thus the drivers would query to get the actual HW frequency rather than the cached one. Do you think keeping these flags would have any impact other than always getting the non-cached rates? -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v5 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
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 Signed-off-by: Taniya Das --- drivers/cpufreq/Kconfig.arm | 10 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 344 ++ 3 files changed, 355 insertions(+) create mode 100644 drivers/cpufreq/qcom-cpufreq-hw.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 52f5f1a..141ec3e 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -312,3 +312,13 @@ config ARM_PXA2xx_CPUFREQ This add the CPUFreq driver support for Intel PXA2xx SOCs. If in doubt, say N. + +config ARM_QCOM_CPUFREQ_HW + bool "QCOM CPUFreq HW driver" + 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 interafce to the High-level OS. +The driver implements the cpufreq driver interface for this HW engine. +Say Y if you want to support CPUFreq HW. diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index fb4a2ec..1226a3e 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)+= tegra124-cpufreq.o obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o ## diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c new file mode 100644 index 000..fa25a95 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#define INIT_RATE 3UL +#define XO_RATE1920UL +#define LUT_MAX_ENTRIES40U +#define CORE_COUNT_VAL(val)(((val) & (GENMASK(18, 16))) >> 16) +#define LUT_ROW_SIZE 32 + +enum { + REG_ENABLE, + REG_LUT_TABLE, + REG_PERF_STATE, + + REG_ARRAY_SIZE, +}; + +struct cpufreq_qcom { + struct cpufreq_frequency_table *table; + struct device *dev; + const u16 *reg_offset; + void __iomem *base; + cpumask_t related_cpus; + unsigned int max_cores; +}; + +static u16 cpufreq_qcom_std_offsets[REG_ARRAY_SIZE] = { + [REG_ENABLE]= 0x0, + [REG_LUT_TABLE] = 0x110, + [REG_PERF_STATE]= 0x920, +}; + +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; + +static int +qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, +unsigned int index) +{ + struct cpufreq_qcom *c = policy->driver_data; + unsigned int offset = c->reg_offset[REG_PERF_STATE]; + + writel_relaxed(index, c->base + offset); + + return 0; +} + +static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) +{ + struct cpufreq_qcom *c; + struct cpufreq_policy *policy; + unsigned int index, offset; + + policy = cpufreq_cpu_get_raw(cpu); + if (!policy) + return 0; + + c = policy->driver_data; + offset = c->reg_offset[REG_PERF_STATE]; + + index = readl_relaxed(c->base + offset); + 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) +{ + struct cpufreq_qcom *c = policy->driver_data; + unsigned int offset; + int index; + + index = cpufreq_table_find_index_l(policy, target_freq); + if (index < 0) + return 0; + + offset = c->reg_offset[REG_PERF_STATE]; + + writel_relaxed(index, c->base + offset); + + return policy->freq_table[index].frequency; +} + +static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) +{ + struct cpufreq_qcom *c; + + c = qcom_freq_domain_map[policy->cpu]; + if (!c) { + pr_err("No scaling support for CPU%d\n", policy->cpu); + return -ENODEV; + } + + cpumask_copy(policy->cpus, &c->related_cpus); + + policy->fast_switch_possible = true; + policy->freq_table = c->table; + polic
[PATCH v5 0/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
[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'. * Remove initialization of 'ret' from function qcom_resources_init and add return -ENODEV based on 'of_get_available_child_count'. * Removed initialization of 'rc' from qcom_cpufreq_fw_driver_probe * Removed module_exit as this driver would not be used as module, also updated the Kconfig to bool from tristate. * Updated the subsystem in device tree bindings. [v1] * Fixed compilation reported by Amit K. 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 | 158 ++ drivers/cpufreq/Kconfig.arm| 10 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 344 + 4 files changed, 513 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.
Re: [PATCH v4 2/2] cpufreq: qcom-fw: Add support for QCOM cpufreq FW driver
Please help review of the new series[v5] which takes care of the below. - 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 On 7/12/2018 2:07 AM, Matthias Kaehlcke wrote: Hi, On Tue, Jun 12, 2018 at 04:32:35PM +0530, Taniya Das wrote: The CPUfreq FW present in some QCOM chipsets offloads the steps necessary for changing the frequency of CPUs. The driver implements the cpufreq driver interface for this firmware. Signed-off-by: Saravana Kannan Signed-off-by: Taniya Das --- drivers/cpufreq/Kconfig.arm | 9 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-fw.c | 336 ++ 3 files changed, 346 insertions(+) create mode 100644 drivers/cpufreq/qcom-cpufreq-fw.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 52f5f1a..2683716 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -312,3 +312,12 @@ config ARM_PXA2xx_CPUFREQ This add the CPUFreq driver support for Intel PXA2xx SOCs. If in doubt, say N. + +config ARM_QCOM_CPUFREQ_FW + bool "QCOM CPUFreq FW driver" + help +Support for the CPUFreq FW driver. +The CPUfreq FW preset in some QCOM chipsets offloads the steps +necessary for changing the frequency of CPUs. The driver +implements the cpufreq driver interface for this firmware. +Say Y if you want to support CPUFreq FW. diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index fb4a2ec..34691a2 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)+= tegra124-cpufreq.o obj-$(CONFIG_ARM_TEGRA186_CPUFREQ)+= tegra186-cpufreq.o obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ)+= vexpress-spc-cpufreq.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_FW) += qcom-cpufreq-fw.o ## diff --git a/drivers/cpufreq/qcom-cpufreq-fw.c b/drivers/cpufreq/qcom-cpufreq-fw.c new file mode 100644 index 000..62f4452 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-fw.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#define INIT_RATE 3UL +#define XO_RATE1920UL +#define LUT_MAX_ENTRIES40U +#define CORE_COUNT_VAL(val)(((val) & (GENMASK(18, 16))) >> 16) +#define LUT_ROW_SIZE 32 + +struct cpufreq_qcom { + struct cpufreq_frequency_table *table; + struct device *dev; + void __iomem *perf_base; + void __iomem *lut_base; + cpumask_t related_cpus; + unsigned int max_cores; Why *max*_cores? This seems to be the number of CPUs in a cluster and qcom_read_lut() expects the core count read from the LUT to match exactly. +static int qcom_read_lut(struct platform_device *pdev, +struct cpufreq_qcom *c) +{ + struct device *dev = &pdev->dev; + u32 data, src, lval, i, core_count, prev_cc, prev_freq, cur_freq; + + c->table = devm_kcalloc(dev, LUT_MAX_ENTRIES + 1, + sizeof(*c->table), GFP_KERNEL); + if (!c->table) + return -ENOMEM; + + for (i = 0; i < LUT_MAX_ENTRIES; i++) { + data = readl_relaxed(c->lut_base + i * LUT_ROW_SIZE); + src = ((data & GENMASK(31, 30)) >> 30); + lval = (data & GENMASK(7, 0)); + core_count = CORE_COUNT_VAL(data); + + if (!src) + c->table[i].frequency = INIT_RATE / 1000; + else + c->table[i].frequency = XO_RATE * lval / 1000; nit: any particular reason to use negative logic here? Why not check for 'src[ != NULL]', which also seems to be the more common case. +static int qcom_get_related_cpus(struct device_node *np, struct cpumask *m) +{ + struct device_node *cpu_np, *freq_np; + int cpu; + + for_each_possible_cpu(cpu) { + cpu_np = of_cpu_device_node_get(cpu); + if (!cpu_np) + continue; + freq_np = of_parse_phandle(cpu_np, "qcom,freq-domain", 0); + if (!freq_np) + continue;
[PATCH v5 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. Signed-off-by: Taniya Das --- .../bindings/cpufreq/cpufreq-qcom-hw.txt | 158 + 1 file changed, 158 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file mode 100644 index 000..52a53e1 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt @@ -0,0 +1,158 @@ +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: + Definition: must be "qcom,cpufreq-hw". + +* Property qcom,freq-domain +Devices supporting freq-domain must set their "qcom,freq-domain" property with +phandle to a freq_domain_table in their DT node. + +* Frequency Domain Table Node + +This describes the frequency domain belonging to a device. +This node can have following properties: + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the HW bases. + +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 = <&freq_domain_table0>; + 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 = <&freq_domain_table0>; + 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 = <&freq_domain_table0>; + 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 = <&freq_domain_table0>; + 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 = <&freq_domain_table1>; + L2_400: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; +
Re: [PATCH v2 1/2] clk: qcom: Add support for RCG to register for DFS
Hello Stephen, Thanks for your review comments. On 7/9/2018 12:34 PM, Stephen Boyd wrote: Quoting Taniya Das (2018-06-28 04:47:30) Dynamic Frequency switch is a feature of clock controller by which request from peripherals allows automatic switching frequency of input clock. There are various performance levels associated to a root clock generator. Register the root clock generators(RCG) to switch to use the dfs clock ops in the cases where DFS is enabled. The DFS clock ops would at runtime read the clock perf level registers to identify the frequencies supported and update the frequency table accordingly. But nobody is really using the frequency table except for clk_round_rate()? Can you add some comments into the commit text and the code indicating how it works in hardware? I think the way it works is by having DFS enabled in the clock controller, and then another register in the QUP register space controls the index that the clk configures itself for. But I'm not clear on if the RCG registers are updated when DFS frequency is set, or if anything is visible from the clk controller hardware besides being in DFS mode and the frequency plan. Sure, added few more details in the next series. Signed-off-by: Taniya Das diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 52208d4..25b0560 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -929,3 +938,208 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw) .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent, }; EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); + +/* Common APIs to be used for DFS based RCGR */ +static int clk_rcg2_calculate_m_and_n(struct clk_hw *hw, u32 *mode, + unsigned long *prate, int level, struct freq_tbl *f) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct clk_hw *phw; Just 'p' for parent is good. Taken care in the next patch. + u32 val, mask, cfg, m_off, n_off, offset; + int i, ret, num_parents; + + offset = SE_PERF_DFSR(level); + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg); + if (ret) + return ret; + + mask = BIT(rcg->hid_width) - 1; + f->pre_div = cfg & mask ? (cfg & mask) : 1; + + *mode = cfg & CFG_MODE_MASK; + *mode >>= CFG_MODE_SHIFT; + + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + num_parents = clk_hw_get_num_parents(hw); + for (i = 0; i < num_parents; i++) { + if (cfg == rcg->parent_map[i].cfg) { + f->src = rcg->parent_map[i].src; + phw = clk_hw_get_parent_by_index(&rcg->clkr.hw, i); + *prate = clk_hw_get_rate(phw); + } + } + + if (!*mode) + return 0; + + /* Calculate M & N values */ + m_off = SE_PERF_M_DFSR(level); + n_off = SE_PERF_N_DFSR(level); + + mask = BIT(rcg->mnd_width) - 1; + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + m_off, &val); Why weird space before regmap_read? removed. + if (ret) { + pr_err("Failed to read M offset register\n"); + return ret; + } + val &= mask; + f->m = val; + + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + n_off, &val); + if (ret) { + pr_err("Failed to read N offset register\n"); + return ret; + } + /* val ~(N-M) */ + val = ~val; + val &= mask; + val += f->m; + f->n = val; + + return 0; +} + +static int clk_rcg2_dfs_populate_freq_table(struct clk_rcg2 *rcg) +{ + struct freq_tbl *dfs_freq_tbl; + int i, j, ret = 0; + unsigned long calc_freq, prate = 0; + u32 mode = 0; + + dfs_freq_tbl = kcalloc(MAX_PERF_LEVEL, sizeof(struct freq_tbl), sizeof(*dfs_freq_tbl) or just call it freq_tbl. We know it's dfs already. Fixed in the next patch. + GFP_KERNEL); + if (!dfs_freq_tbl) + return -ENOMEM; + + for (i = 0; i < MAX_PERF_LEVEL; i++) { + ret = clk_rcg2_calculate_m_and_n(&rcg->clkr.hw, &mode, &prate, +i, &dfs_freq_tbl[i]); Why can't this function return the frequency? Or 0 if it failed for some reason? Sure, have taken care in the next patch. + if (ret) { + kfree(dfs_freq_tbl); + return ret; + } + + calc_freq = calc_rate(prate, dfs_freq_tbl[i].m, + dfs_freq_tbl[i].n, mode, + dfs_freq_tbl[i].pre_div); Because this is not so good looking. + /* Check for dupl
[PATCH v3 0/2] clk: qcom: Add support for RCG to register for DFS
[v3] * Rename clk_rcg2_calculate_m_and_n with clk_rcg2_calculate_freq, as this function would now calculate the frequency. * Rename dfs_freq_tbl to freq_tbl. * Remove the logic to remove duplicate frequencies. * Remove recalc_rate & set_rate clock ops. * clk_rcg2_dfs_ops clock ops is static. * Override the clock ops only if DFS mode is enabled. * qcom_cc_register_rcg_dfs uses regmap instead of device. * Few cleanups : Remove DFS probing after registering clocks. sizeof(*init), sizeof(*freq_tbl). [v2] * Move the dfs register function 'qcom_cc_register_rcg_dfs' to clk-rcg2.c instead of common.c * At boot read the DFS enable register and override the clk_ops to be used for dfs or non-dfs RCGs. * Remove flag 'dfs_enabled'. * Remove functions 'clk_rcg2_dfs_determine_rate_lazy' * Remove 'struct dfs_table *dfs_entry' * Remove '_freq_tbl_determine_dfs_rate' * Combine the function 'clk_index_pre_div_and_mode' and 'calculate_m_and_n' to a single function and named it 'clk_rcg2_calculate_m_and_n'. * Remove taking M/N/PERF offsets as function arguments. * Add clocks in gcc-sdm845.c the DFS clock array to register. [v1] * Update SPDX for files. * Add new clk_ops for DFS mode which would be used if dfs is enabled, else fall back to the clk_rcg2_shared_ops. * Use kcalloc in place kzalloc. * Fixed the return type for 'clk_parent_index_pre_div_and_mode' which is now renamed to 'clk_index_pre_div_and_mode'. * Removed return of -EPERM from 'clk_rcg2_set_rate' and new dfs clk_ops is introduced. * Pass frequency table entry structure to function calculate_m_and_n. * Remove desc from qcom_cc_register_rcg_dfs and instead pass array of clk_rcg2. * Add a dfs_enable flag to identify if dfs mode is enabled. In the cases where a RCG requires a Dynamic Frequency switch support requires to register which would at runtime read the clock perf level registers to identify the frequencies supported and update the frequency table accordingly. Taniya Das (2): clk: qcom: Add support for RCG to register for DFS clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845 drivers/clk/qcom/clk-rcg.h| 2 + drivers/clk/qcom/clk-rcg2.c | 173 ++ drivers/clk/qcom/gcc-sdm845.c | 25 ++ 3 files changed, 200 insertions(+) -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v3 1/2] clk: qcom: Add support for RCG to register for DFS
Dynamic Frequency switch is a feature of clock controller by which request from peripherals allows automatic switching frequency of input clock without SW intervention. There are various performance levels associated with a root clock. When the input performance state changes, the source clocks and division ratios of the new performance state are loaded on to RCG via HW and the RCG switches to new clock frequency when the RCG is in DFS HW enabled mode. Register the root clock generators(RCG) to switch to use the dfs clock ops in the cases where DFS is enabled. The clk_round_rate() called by the clock consumer would invoke the dfs determine clock ops and would read the DFS performance level registers to identify all the frequencies supported and update the frequency table. The DFS clock consumers would maintain these frequency mapping and request the desired performance levels. Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-rcg.h | 2 + drivers/clk/qcom/clk-rcg2.c | 173 2 files changed, 175 insertions(+) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index b209a2f..bffb625 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -161,4 +161,6 @@ struct clk_rcg2 { extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_rcg2_shared_ops; +extern int qcom_cc_register_rcg_dfs(struct regmap *regmap, +struct clk_rcg2 **rcgs, int num_clks); #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 52208d4..f8f1417 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -40,6 +41,14 @@ #define N_REG 0xc #define D_REG 0x10 +/* Dynamic Frequency Scaling */ +#define MAX_PERF_LEVEL 8 +#define SE_CMD_DFSR_OFFSET 0x14 +#define SE_CMD_DFS_EN BIT(0) +#define SE_PERF_DFSR(level)(0x1c + 0x4 * (level)) +#define SE_PERF_M_DFSR(level) (0x5c + 0x4 * (level)) +#define SE_PERF_N_DFSR(level) (0x9c + 0x4 * (level)) + enum freq_policy { FLOOR, CEIL, @@ -929,3 +938,167 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw) .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent, }; EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); + +/* Common APIs to be used for DFS based RCGR */ +static unsigned long clk_rcg2_calculate_freq(struct clk_hw *hw, + int level, struct freq_tbl *f) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct clk_hw *p; + unsigned long prate = 0; + u32 val, mask, cfg, m_off, n_off, offset, mode; + int i, ret, num_parents; + + offset = SE_PERF_DFSR(level); + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg); + if (ret) + return ret; + + mask = BIT(rcg->hid_width) - 1; + f->pre_div = cfg & mask ? (cfg & mask) : 1; + + mode = cfg & CFG_MODE_MASK; + mode >>= CFG_MODE_SHIFT; + + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + num_parents = clk_hw_get_num_parents(hw); + for (i = 0; i < num_parents; i++) { + if (cfg == rcg->parent_map[i].cfg) { + f->src = rcg->parent_map[i].src; + p = clk_hw_get_parent_by_index(&rcg->clkr.hw, i); + prate = clk_hw_get_rate(p); + } + } + + if (!mode) + goto done; + + /* Calculate M & N values */ + m_off = SE_PERF_M_DFSR(level); + n_off = SE_PERF_N_DFSR(level); + + mask = BIT(rcg->mnd_width) - 1; + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + m_off, &val); + if (ret) { + pr_err("Failed to read M offset register\n"); + return ret; + } + val &= mask; + f->m = val; + + ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + n_off, &val); + if (ret) { + pr_err("Failed to read N offset register\n"); + return ret; + } + /* val ~(N-M) */ + val = ~val; + val &= mask; + val += f->m; + f->n = val; +done: + return calc_rate(prate, f->m, f->n, mode, f->pre_div); +} + +static int clk_rcg2_dfs_populate_freq_table(struct clk_rcg2 *rcg) +{ + struct freq_tbl *freq_tbl; + unsigned long calc_freq; + int i; + + freq_tbl = kcalloc(MAX_PERF_LEVEL, sizeof(*freq_tbl), + GFP_KERNEL); + if (!freq_tbl) + return -ENOMEM; + + for (i = 0; i < MAX_PERF_LEVEL; i++) { + calc_freq = clk_rcg2_calculate_freq(&rcg->clkr.hw, +
[PATCH v3 2/2] clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845
QUPv3 clocks support DFS and thus register the RCGs which require support for the same. Signed-off-by: Taniya Das --- drivers/clk/qcom/gcc-sdm845.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 0f694ed..305deca 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -3460,9 +3460,29 @@ enum { }; MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table); +static struct clk_rcg2 *gcc_dfs_clocks[] = { + &gcc_qupv3_wrap0_s0_clk_src, + &gcc_qupv3_wrap0_s1_clk_src, + &gcc_qupv3_wrap0_s2_clk_src, + &gcc_qupv3_wrap0_s3_clk_src, + &gcc_qupv3_wrap0_s4_clk_src, + &gcc_qupv3_wrap0_s5_clk_src, + &gcc_qupv3_wrap0_s6_clk_src, + &gcc_qupv3_wrap0_s7_clk_src, + &gcc_qupv3_wrap1_s0_clk_src, + &gcc_qupv3_wrap1_s1_clk_src, + &gcc_qupv3_wrap1_s2_clk_src, + &gcc_qupv3_wrap1_s3_clk_src, + &gcc_qupv3_wrap1_s4_clk_src, + &gcc_qupv3_wrap1_s5_clk_src, + &gcc_qupv3_wrap1_s6_clk_src, + &gcc_qupv3_wrap1_s7_clk_src, +}; + static int gcc_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; + int ret; regmap = qcom_cc_map(pdev, &gcc_sdm845_desc); if (IS_ERR(regmap)) @@ -3472,6 +3492,11 @@ static int gcc_sdm845_probe(struct platform_device *pdev) regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3); regmap_update_bits(regmap, 0x71028, 0x3, 0x3); + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) + return ret; + return qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap); } -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH] clk: qcom: Update SPDX headers for common files
SPDX headers updated for common/branch/pll/regmap files. Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-alpha-pll.c | 10 +- drivers/clk/qcom/clk-alpha-pll.h | 14 ++ drivers/clk/qcom/clk-branch.c| 10 +- drivers/clk/qcom/clk-branch.h| 14 ++ drivers/clk/qcom/clk-regmap.c| 10 +- drivers/clk/qcom/clk-regmap.h| 14 ++ drivers/clk/qcom/common.c| 10 +- drivers/clk/qcom/common.h| 15 +++ 8 files changed, 13 insertions(+), 84 deletions(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 3c49a60..a91d97c 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index f981b48..66755f0 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -1,15 +1,5 @@ -/* - * Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_ALPHA_PLL_H__ #define __QCOM_CLK_ALPHA_PLL_H__ diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index c58c553..bc2205c 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h index 1702efb..b3561e0 100644 --- a/drivers/clk/qcom/clk-branch.h +++ b/drivers/clk/qcom/clk-branch.h @@ -1,15 +1,5 @@ -/* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_BRANCH_H__ #define __QCOM_CLK_BRANCH_H__ diff --git a/drivers/clk/qcom/clk-regmap.c b/drivers/clk/qcom/clk-regmap.c index 1c856d3..ce80db2 100644 --- a/drivers/clk/qcom/clk-regmap.c +++ b/drivers/clk/qcom/clk-regmap.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/qcom/clk-regmap.h b/drivers/clk/qcom/clk-regmap.h index 90d95cd..6cfc1bc 100644 --- a/drivers/clk/qcom/clk-regmap.h +++ b/drivers/clk/qcom/clk-regmap.h @@ -1,15 +1,5 @@ -/* - * Copyright
Re: [PATCH v3 3/3] clk: qcom: Add display clock controller driver for SDM845
Hello Stephen, On 7/13/2018 1:55 PM, spa...@codeaurora.org wrote: On 2018-07-13 01:11, Stephen Boyd wrote: Quoting Taniya Das (2018-07-12 10:21:33) ++ Display driver team, On 7/9/2018 8:36 PM, Stephen Boyd wrote: > Quoting Taniya Das (2018-07-09 02:34:07) >> >> >> On 7/9/2018 1:07 PM, Stephen Boyd wrote: >>> Quoting Taniya Das (2018-07-09 00:07:21) >>>> >>>> >>>> On 7/9/2018 11:46 AM, Stephen Boyd wrote: >>>>>> >>>>>> > Why is the nocache flag needed? Applies to all clks in this file. >>>>>> > >>>>>> >>>>>> This flag is required for all RCGs whose PLLs are controlled outside the >>>>>> clock controller. The display code would require the recalculated rate >>>>>> always. >>>>> >>>>> Right. Why is the PLL controlled outside of the clock controller? The >>>>> rate should propagate upward to the PLL from here, so who's going >>>>> outside of that? >>>>> >>>> The DSI0/1 PLL are not part of the display clock controller, but in the >>>> display subsystem which are managed by the DRM drivers. When DRM drivers >>>> query for the rate clock driver should always return the non cached rates. >>> >>> Why? Is the DSI PLL changing rate all the time, randomly, without going >>> through the clk APIs to do so? >>> >> >> Hmm, I am afraid I do not have an answer for this, but this was the >> requirement to always return the non cached rates from the clock driver. >> > > Ok. Who knows about this requirement? Can we add someone from the > display driver to understand more? > As per my discussions offline with the display teams, There is a use-case where the clock framework is unaware of the PLL VCO frequency change and thus the drivers would query to get the actual HW frequency rather than the cached one. Do you think keeping these flags would have any impact other than always getting the non-cached rates? The flag will make it so clk_get_rate() works in spite of something changing the frequency behind the framework's back, but I want to understand what and why it's changing without framework involvement. We shouldn't need the flag here, because this flag is typically for clks that are controlled by some other entity that the kernel doesn't have control over. In this case, it seems like we have full control of the clk tree for the display PLL down to this clk, so it should be perfectly fine to not have this flag. The presence of the flag means that the display driver is doing something wrong. These clocks are sourced from DSI PLL. In dsi command mode there is an idle use case when there is no activity on display, we switch of the source DSI PLL to save power by calling clk_disable_unprepare(). In this scenario if some client queries the clk_get_rate(), then if NO_CACHE flag is used the clk driver will return the cached rate which is some non-zero value set when we last called clk_set_rate(), before enabling the clock, whereas actually in HW this clk is disabled. So we used the NO_CACHE flag for the call to land in clk_recalc_rate and we return zero if the PLL is disabled. I remember some customer had scripts that runs through all the clocks during idle screen scenario and call clk_get_rate(), where they complained display clk_get_rate returns none zero value. Do you think the clock driver needs any update for flag for the next series? -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH 2/2] dt-bindings: clock: Introduce QCOM RPMh clock bindings
Thanks Stephen for the review. On 4/6/2018 4:50 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-03-28 23:17:53) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt new file mode 100644 index 000..8222c88 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt Can the file name be qcom,rpmh-clk? Sure will update the file name. @@ -0,0 +1,22 @@ +Qualcomm Technologies, Inc. RPMh Clocks +--- + +Resource Power Manager Hardened (RPMh) manages shared resources on +some Qualcomm Technologies Inc. SoCs. It accepts clock requests from +other hardware subsystems via RSC to control clocks. + +Required properties : +- compatible : shall contain "qcom,rpmh-clk-sdm845" + +- #clock-cells : must contain 1 + +Example : + +#include + + &apps_rsc { + clock_rpmh: qcom,rpmhclk { Should say clock-controller for node name. Would fix it in the next patch. + compatible = "qcom,rpmh-clk-sdm845"; + #clock-cells = <1>; Is this tabbed out correctly? Will fix the tabs in the next patch. + }; + }; -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v2 0/2] Add QCOM RPMh Clock driver
[v2] * Addressed comments from Stephen * Addressed comments from Evan This patch series adds a driver and device tree documentation binding for the clock control via Resource Power Manager-hardened (RPMh) on some Qualcomm Technologies, Inc, SoCs such as SDM845. The clock RPMh driver would send requests for the RPMh managed clock resources. The RPMh clock driver depends upon the RPMh driver [1] and command DB driver [2] which are both still undergoing review. Thanks, Taniya [1]: https://lkml.org/lkml/2018/3/9/979 [2]: https://lkml.org/lkml/2018/3/14/787 Amit Nischal (2): clk: qcom: clk-rpmh: Add QCOM RPMh clock driver dt-bindings: clock: Introduce QCOM RPMh clock bindings .../devicetree/bindings/clock/qcom,rpmh-clk.txt | 22 ++ drivers/clk/qcom/Kconfig| 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-rpmh.c | 394 + include/dt-bindings/clock/qcom,rpmh.h | 25 ++ 5 files changed, 451 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,rpmh-clk.txt create mode 100644 drivers/clk/qcom/clk-rpmh.c create mode 100644 include/dt-bindings/clock/qcom,rpmh.h -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[[PATCH v2] 1/2] clk: qcom: clk-rpmh: Add QCOM RPMh clock driver
From: Amit Nischal Add the RPMh clock driver to control the RPMh managed clock resources on some of the Qualcomm Technologies, Inc. SoCs. Signed-off-by: David Collins Signed-off-by: Amit Nischal Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-rpmh.c | 394 ++ include/dt-bindings/clock/qcom,rpmh.h | 25 +++ 4 files changed, 429 insertions(+) create mode 100644 drivers/clk/qcom/clk-rpmh.c create mode 100644 include/dt-bindings/clock/qcom,rpmh.h diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index fbf4532..3697a6a 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -112,6 +112,15 @@ config IPQ_GCC_8074 i2c, USB, SD/eMMC, etc. Select this for the root clock of ipq8074. +config MSM_CLK_RPMH + tristate "RPMh Clock Driver" + depends on COMMON_CLK_QCOM && QCOM_RPMH + help +RPMh manages shared resources on some Qualcomm Technologies, Inc. +SoCs. It accepts requests from other hardware subsystems via RSC. +Say Y if you want to support the clocks exposed by RPMh on +platforms such as sdm845. + config MSM_GCC_8660 tristate "MSM8660 Global Clock Controller" depends on COMMON_CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 230332c..b7da05b 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_IPQ_GCC_8074) += gcc-ipq8074.o obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o +obj-$(CONFIG_MSM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c new file mode 100644 index 000..763401f --- /dev/null +++ b/drivers/clk/qcom/clk-rpmh.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" + +#define CLK_RPMH_ARC_EN_OFFSET 0 +#define CLK_RPMH_VRM_EN_OFFSET 4 +#define CLK_RPMH_VRM_OFF_VAL 0 +#define CLK_RPMH_VRM_ON_VAL 1 +#define CLK_RPMH_APPS_RSC_AO_STATE_MASK (BIT(RPMH_WAKE_ONLY_STATE) | \ +BIT(RPMH_ACTIVE_ONLY_STATE)) +#define CLK_RPMH_APPS_RSC_STATE_MASK (BIT(RPMH_WAKE_ONLY_STATE) | \ + BIT(RPMH_ACTIVE_ONLY_STATE) | \ + BIT(RPMH_SLEEP_STATE)) +struct clk_rpmh { + struct clk_hw hw; + const char *res_name; + u32 res_addr; + u32 res_en_offset; + u32 res_on_val; + u32 res_off_val; + u32 state; + u32 aggr_state; + u32 last_sent_aggr_state; + u32 valid_state_mask; + struct rpmh_client *rpmh_client; + unsigned long rate; + struct clk_rpmh *peer; +}; + +struct rpmh_cc { + struct clk_onecell_data data; + struct clk *clks[]; +}; + +struct clk_rpmh_desc { + struct clk_hw **clks; + size_t num_clks; +}; + +static DEFINE_MUTEX(rpmh_clk_lock); + +#define __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \ + _res_en_offset, _res_on, _res_off, _rate, \ + _state_mask, _state_on_mask)\ + static struct clk_rpmh _platform##_##_name_active;\ + static struct clk_rpmh _platform##_##_name = {\ + .res_name = _res_name,\ + .res_en_offset = _res_en_offset, \ + .res_on_val = _res_on,\ + .res_off_val = _res_off, \ + .rate = _rate,\ + .peer = &_platform##_##_name_active, \ + .valid_state_mask = _state_mask, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpmh_ops, \ + .name = #_name, \ + },\ + };\ + static struct clk_rpmh _platform##_##_name_active = { \ + .res_name = _res_name,
[[PATCH v2] 2/2] dt-bindings: clock: Introduce QCOM RPMh clock bindings
From: Amit Nischal Add RPMh clock device bindings for Qualcomm Technology Inc's SoCs. These devices would be used for communicating resource state requests to control the clocks managed by RPMh. Signed-off-by: Amit Nischal Signed-off-by: Taniya Das --- .../devicetree/bindings/clock/qcom,rpmh-clk.txt| 22 ++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,rpmh-clk.txt diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmh-clk.txt b/Documentation/devicetree/bindings/clock/qcom,rpmh-clk.txt new file mode 100644 index 000..4ade82b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,rpmh-clk.txt @@ -0,0 +1,22 @@ +Qualcomm Technologies, Inc. RPMh Clocks +--- + +Resource Power Manager Hardened (RPMh) manages shared resources on +some Qualcomm Technologies Inc. SoCs. It accepts clock requests from +other hardware subsystems via RSC to control clocks. + +Required properties : +- compatible : shall contain "qcom,rpmh-clk-sdm845" + +- #clock-cells : must contain 1 + +Example : + +#include + + &apps_rsc { + rpmh: clock-controller { + compatible = "qcom,rpmh-clk-sdm845"; + #clock-cells = <1>; + }; + }; -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v2 0/3] Update reset and poll logic for GDSCs
[v2] * Addressed review comments given in v1 series This series implements the below logic for the GDSCs 1. logic to reset the AON logic before or assert/deassert the block control reset removing the clamp io for few GDSCs on SDM845 SoC. 2. It also introduces the requirement to poll for higher timeout values for few of the GDSCs. 3. There is a new poll register for the GDSCs on SDM845 SoCs which needs to be polled for the correct hardware status of the GDSCs. Amit Nischal (3): clk: qcom: gdsc: Add support to reset AON and block reset logic clk: qcom: gdsc: Add support to poll for higher timeout value clk: qcom: gdsc: Add support to poll CFG register to check GDSC state drivers/clk/qcom/gdsc.c | 63 +++-- drivers/clk/qcom/gdsc.h | 5 +++- 2 files changed, 60 insertions(+), 8 deletions(-) -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v2 3/3] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
From: Amit Nischal The default behavior of the GDSC enable/disable sequence is to poll the status bits of either the actual GDSCR or the corresponding HW_CTRL registers. On targets which have support for a CFG_GDSCR register, the status bits might not show the correct state of the GDSC, especially in the disable sequence, where the status bit will be cleared even before the core is completely power collapsed. On targets with this issue, poll the power on/off bits in the CFG_GDSCR register instead to correctly determine the GDSC state. Signed-off-by: Amit Nischal Signed-off-by: Taniya Das --- drivers/clk/qcom/gdsc.c | 39 +++ drivers/clk/qcom/gdsc.h | 1 + 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index cb61c15..2dda2d5 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -33,6 +33,11 @@ #define GMEM_CLAMP_IO_MASK BIT(0) #define GMEM_RESET_MASKBIT(4) +/* CFG_GDSCR */ +#define GDSC_POWER_UP_COMPLETE BIT(16) +#define GDSC_POWER_DOWN_COMPLETE BIT(15) +#define CFG_GDSCR_OFFSET 0x4 + /* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */ #define EN_REST_WAIT_VAL (0x2 << 20) #define EN_FEW_WAIT_VAL(0x8 << 16) @@ -64,18 +69,43 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en) return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val); } +static int gdsc_is_enabled_by_poll_cfg_reg(struct gdsc *sc, bool en) +{ + u32 val; + int ret; + + ret = regmap_read(sc->regmap, sc->gdscr + CFG_GDSCR_OFFSET, &val); + if (ret) + return ret; + + if (en) + return !!(val & GDSC_POWER_UP_COMPLETE); + + return !(val & GDSC_POWER_DOWN_COMPLETE); +} + static int gdsc_poll_status(struct gdsc *sc, unsigned int reg, bool en) { ktime_t start; start = ktime_get(); do { - if (gdsc_is_enabled(sc, reg) == en) - return 0; + if (sc->flags & POLL_CFG_GDSCR) { + if (gdsc_is_enabled_by_poll_cfg_reg(sc, en) == en) + return 0; + } else { + if (gdsc_is_enabled(sc, reg) == en) + return 0; + } } while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US); - if (gdsc_is_enabled(sc, reg) == en) - return 0; + if (sc->flags & POLL_CFG_GDSCR) { + if (gdsc_is_enabled_by_poll_cfg_reg(sc, en) == en) + return 0; + } else { + if (gdsc_is_enabled(sc, reg) == en) + return 0; + } return -ETIMEDOUT; } @@ -254,6 +284,7 @@ static int gdsc_disable(struct generic_pm_domain *domain) udelay(1); reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr; + ret = gdsc_poll_status(sc, reg, true); if (ret) return ret; diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index 9279278..0f992e8 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -55,6 +55,7 @@ struct gdsc { #define HW_CTRLBIT(2) #define SW_RESET BIT(3) #define AON_RESET BIT(4) +#define POLL_CFG_GDSCR BIT(5) struct reset_controller_dev *rcdev; unsigned int*resets; unsigned intreset_count; -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v2 0/3] Update reset and poll logic for GDSCs
[v2] * Addressed review comments given in v1 series This series implements the below logic for the GDSCs 1. logic to reset the AON logic before or assert/deassert the block control reset removing the clamp io for few GDSCs on SDM845 SoC. 2. It also introduces the requirement to poll for higher timeout values for few of the GDSCs. 3. There is a new poll register for the GDSCs on SDM845 SoCs which needs to be polled for the correct hardware status of the GDSCs. Amit Nischal (3): clk: qcom: gdsc: Add support to reset AON and block reset logic clk: qcom: gdsc: Add support to poll for higher timeout value clk: qcom: gdsc: Add support to poll CFG register to check GDSC state drivers/clk/qcom/gdsc.c | 63 +++-- drivers/clk/qcom/gdsc.h | 5 +++- 2 files changed, 60 insertions(+), 8 deletions(-) -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v2 2/3] clk: qcom: gdsc: Add support to poll for higher timeout value
From: Amit Nischal For some gdscs, it might take longer time up to 500us for updating their status. Update the timeout value for all GDSC polling status. Signed-off-by: Amit Nischal Signed-off-by: Taniya Das --- drivers/clk/qcom/gdsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index 266fefa..cb61c15 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -41,7 +41,7 @@ #define RETAIN_MEM BIT(14) #define RETAIN_PERIPH BIT(13) -#define TIMEOUT_US 100 +#define TIMEOUT_US 500 #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd) -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v2 1/3] clk: qcom: gdsc: Add support to reset AON and block reset logic
From: Amit Nischal For some of the gdsc power domains, there could be need to reset the AON logic or assert/deassert the block control reset before removing the clamp_io. Add support for the same by introducing new flags SW_RESET and AON_RESET. Both SW reset and AON reset requires to be asserted for at least 1us before being de-asserted. Signed-off-by: Taniya Das Signed-off-by: Amit Nischal --- drivers/clk/qcom/gdsc.c | 22 -- drivers/clk/qcom/gdsc.h | 4 +++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index a4f3580..266fefa 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,6 +31,7 @@ #define HW_CONTROL_MASKBIT(1) #define SW_COLLAPSE_MASK BIT(0) #define GMEM_CLAMP_IO_MASK BIT(0) +#define GMEM_RESET_MASKBIT(4) /* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */ #define EN_REST_WAIT_VAL (0x2 << 20) @@ -166,6 +167,14 @@ static inline void gdsc_assert_clamp_io(struct gdsc *sc) GMEM_CLAMP_IO_MASK, 1); } +static inline void gdsc_assert_reset_aon(struct gdsc *sc) +{ + regmap_update_bits(sc->regmap, sc->clamp_io_ctrl, + GMEM_RESET_MASK, 1); + udelay(1); + regmap_update_bits(sc->regmap, sc->clamp_io_ctrl, + GMEM_RESET_MASK, 0); +} static int gdsc_enable(struct generic_pm_domain *domain) { struct gdsc *sc = domain_to_gdsc(domain); @@ -174,8 +183,17 @@ static int gdsc_enable(struct generic_pm_domain *domain) if (sc->pwrsts == PWRSTS_ON) return gdsc_deassert_reset(sc); - if (sc->flags & CLAMP_IO) + if (sc->flags & SW_RESET) { + gdsc_assert_reset(sc); + udelay(1); + gdsc_deassert_reset(sc); + } + + if (sc->flags & CLAMP_IO) { + if (sc->flags & AON_RESET) + gdsc_assert_reset_aon(sc); gdsc_deassert_clamp_io(sc); + } ret = gdsc_toggle_logic(sc, true); if (ret) diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index 3964834..9279278 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -53,6 +53,8 @@ struct gdsc { #define VOTABLEBIT(0) #define CLAMP_IO BIT(1) #define HW_CTRLBIT(2) +#define SW_RESET BIT(3) +#define AON_RESET BIT(4) struct reset_controller_dev *rcdev; unsigned int*resets; unsigned intreset_count; -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Re: [PATCH 2/3] clk: qcom: gdsc: Add support to poll for higher timeout value
Hello Stephen, Thanks for the review comments. On 4/6/2018 4:54 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-04-02 03:45:44) From: Amit Nischal For some gdscs, it might take longer time up to 500us for updating their status. So add support for the same by defining a new flag 'GDS_TIMEOUT' to mark such gdsc in order to poll their status for longer timeout value. Signed-off-by: Amit Nischal Signed-off-by: Taniya Das --- Let's just increase the timeout to 500 if it's required? This is a timeout, so we're not really expecting to hit it anyway so optimizing the uncommon case is not useful. -- Will fix this in the next series. To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH 3/3] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
Hello Stephen, Thanks for the review comments. On 4/6/2018 10:10 PM, Stephen Boyd wrote: Quoting Taniya Das (2018-04-02 03:45:45) diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index e89584e..e0c83ba 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -83,6 +88,38 @@ static int gdsc_poll_status(struct gdsc *sc, unsigned int reg, bool en) return -ETIMEDOUT; } +static int gdsc_is_enabled_by_poll_cfg_reg(struct gdsc *sc, bool en) +{ + u32 val; + int ret; + + ret = regmap_read(sc->regmap, sc->gdscr + CFG_GDSCR_OFFSET, &val); + if (ret) + return ret; + + if (en) + return !!(val & GDSC_POWER_UP_COMPLETE); + else + return !(val & GDSC_POWER_DOWN_COMPLETE); Make this into if (en) return ... return ... Will fix this in the next series. +} + +static int gdsc_poll_cfg_status(struct gdsc *sc, bool en) +{ + ktime_t start = ktime_get(); + ktime_t timeout = + (sc->flags & GDS_TIMEOUT) ? TIMEOUT_US_GDS : TIMEOUT_US; + + do { + if (gdsc_is_enabled_by_poll_cfg_reg(sc, en) == en) + return 0; + } while (ktime_us_delta(ktime_get(), start) < timeout); + + if (gdsc_is_enabled_by_poll_cfg_reg(sc, en) == en) + return 0; + + return -ETIMEDOUT; +} + static int gdsc_toggle_logic(struct gdsc *sc, bool en) { int ret; @@ -106,6 +143,9 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en) return 0; } + if (sc->flags & POLL_CFG_GDSCR) + return gdsc_poll_cfg_status(sc, en); + if (sc->gds_hw_ctrl) { status_reg = sc->gds_hw_ctrl; /* @@ -258,8 +298,12 @@ static int gdsc_disable(struct generic_pm_domain *domain) */ udelay(1); - reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr; - ret = gdsc_poll_status(sc, reg, true); + if (sc->flags & POLL_CFG_GDSCR) { + ret = gdsc_poll_cfg_status(sc, true); + } else { + reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr; + ret = gdsc_poll_status(sc, reg, true); + } Maybe this can be pushed into the gdsc_poll_status() function so that we can keep the "how do we poll status bit" logic in one place. Yes, I will push the logic in the gdsc_poll_status() in the next series. if (ret) return ret; } -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v4 0/2] Add QCOM graphics clock controller driver for SDM845
Changes in v4: * Cleanup the GPUCC code to keep only the clocks which would be requested from the GPU client SW. * Clean up of code as well as header file clock IDs. * Due to the above cleanup the patches to enable/disable clocks for GPU GDSC requirement is not supported : https://patchwork.kernel.org/patch/10563889/ * The GPU_GX RCG support is also removed from the main driver, so the corresponding RCG ops are removed : https://patchwork.kernel.org/patch/10563891/ Changes in v3: * Modified the determine_rate() op to use the min/max rate range to round the requested rate within the set_rate range. With this, requested set rate will always stay within the limits. Changes in v2: Addressed review comments given by Stephen: https://lkml.org/lkml/2018/6/6/294 * Introduce clk_rcg2_gfx3d_determine_rate ops to return the best parent as 'gpucc_pll0_even' and best parent rate as twice of the requested rate always. This will eliminate the need of frequency table as source and div-2 are fixed for gfx3d_clk_src. Also modified the clk_rcg2_set_rate ops to configure the fixed source and div. * Add support to check if requested rate falls within allowed set_rate range. This will not let the source gpucc_pll0 to go out of the supported range and also client can request the rate within the range. * Fixed comment text in probe function and added module description for GPUCC driver. The graphics clock driver depends upon the below change. https://lkml.org/lkml/2018/6/23/108 Changes in v1: This patch series adds support for graphics clock controller for SDM845. Below is the brief description for each change: 1. For some of the GDSCs, there is requirement to enable/disable the few clocks before turning on/off the gdsc power domain. This patch will add support to enable/disable the clock associated with the gdsc along with power domain on/off callbacks. 2. To turn on the gpu_gx_gdsc, there is a hardware requirement to turn on the root clock (GFX3D RCG) first which would be the turn on signal for the gdsc along with the SW_COLLAPSE. As per the current implementation of clk_rcg2_shared_ops, it clears the root_enable bit in the enable() clock ops. But due to the above said requirement for GFX3D shared RCG, root_enable bit would be already set by gdsc driver and rcg2_shared_ops should not clear the root unless the disable() is called. This patch add support for the same by reusing the existing clk_rcg2_shared_ops and deriving "clk_rcg2_gfx3d_ops" clk_ops for GFX3D clock to take care of the root set/clear requirement. 3. Add device tree bindings for graphics clock controller for SDM845. 4. Add graphics clock controller (GPUCC) driver for SDM845. [v1] : https://lore.kernel.org/patchwork/project/lkml/list/?series=348697 [v2] : https://lore.kernel.org/patchwork/project/lkml/list/?series=359012 Amit Nischal (2): dt-bindings: clock: Introduce QCOM Graphics clock bindings clk: qcom: Add graphics clock controller driver for SDM845 .../devicetree/bindings/clock/qcom,gpucc.txt | 18 ++ drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gpucc-sdm845.c| 231 + include/dt-bindings/clock/qcom,gpucc-sdm845.h | 24 +++ 5 files changed, 283 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,gpucc.txt create mode 100644 drivers/clk/qcom/gpucc-sdm845.c create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v4 2/2] clk: qcom: Add graphics clock controller driver for SDM845
From: Amit Nischal Add support for the graphics clock controller found on SDM845 based devices. This would allow graphics drivers to probe and control their clocks. Signed-off-by: Amit Nischal Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig| 9 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gpucc-sdm845.c | 231 3 files changed, 241 insertions(+) create mode 100644 drivers/clk/qcom/gpucc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index a611531..6f3e466 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -273,6 +273,15 @@ config SDM_GCC_845 Say Y if you want to use peripheral devices such as UART, SPI, i2C, USB, UFS, SDDC, PCIe, etc. +config SDM_GPUCC_845 + tristate "SDM845 Graphics Clock Controller" + depends on COMMON_CLK_QCOM + select SDM_GCC_845 + help + Support for the graphics clock controller on SDM845 devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + config SDM_VIDEOCC_845 tristate "SDM845 Video Clock Controller" depends on COMMON_CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 981882e..6ed2827 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o +obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c new file mode 100644 index 000..11222f4 --- /dev/null +++ b/drivers/clk/qcom/gpucc-sdm845.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "gdsc.h" + +#define CX_GMU_CBCR_SLEEP_MASK 0xf +#define CX_GMU_CBCR_SLEEP_SHIFT4 +#define CX_GMU_CBCR_WAKE_MASK 0xf +#define CX_GMU_CBCR_WAKE_SHIFT 8 +#define CLK_DIS_WAIT_SHIFT 12 +#define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT) + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL1_OUT_EVEN, + P_GPU_CC_PLL1_OUT_MAIN, + P_GPU_CC_PLL1_OUT_ODD, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_0[] = { + "bi_tcxo", + "gpu_cc_pll1", + "gcc_gpu_gpll0_clk_src", + "gcc_gpu_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct alpha_pll_config gpu_cc_pll1_config = { + .l = 0x1a, + .alpha = 0xaab, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x100, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(1920, P_BI_TCXO, 1, 0, 0), + F(2, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + F(5, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_names = gpu_cc_parent_names_0, + .num_parents = 6, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.in
[PATCH v4 1/2] dt-bindings: clock: Introduce QCOM Graphics clock bindings
From: Amit Nischal Add device tree bindings for graphics clock controller for Qualcomm Technology Inc's SDM845 SoCs. Signed-off-by: Amit Nischal --- .../devicetree/bindings/clock/qcom,gpucc.txt | 18 include/dt-bindings/clock/qcom,gpucc-sdm845.h | 24 ++ 2 files changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,gpucc.txt create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt new file mode 100644 index 000..93752db --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt @@ -0,0 +1,18 @@ +Qualcomm Graphics Clock & Reset Controller Binding +-- + +Required properties : +- compatible : shall contain "qcom,sdm845-gpucc". +- reg : shall contain base register location and length. +- #clock-cells : from common clock binding, shall contain 1. +- #reset-cells : from common reset binding, shall contain 1. +- #power-domain-cells : from generic power domain binding, shall contain 1. + +Example: + gpucc: clock-controller@509 { + compatible = "qcom,sdm845-gpucc"; + reg = <0x509 0x9000>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h new file mode 100644 index 000..9690d90 --- /dev/null +++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_GPU_CC_SDM845_H +#define _DT_BINDINGS_CLK_SDM_GPU_CC_SDM845_H + +/* GPU_CC clock registers */ +#define GPU_CC_CX_GMU_CLK 0 +#define GPU_CC_CXO_CLK 1 +#define GPU_CC_GMU_CLK_SRC 2 +#define GPU_CC_PLL13 + +/* GPU_CC Resets */ +#define GPUCC_GPU_CC_CX_BCR0 +#define GPUCC_GPU_CC_GMU_BCR 1 +#define GPUCC_GPU_CC_XO_BCR2 + +/* GPU_CC GDSCRs */ +#define GPU_CX_GDSC0 +#define GPU_GX_GDSC1 + +#endif -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v10 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. Signed-off-by: Taniya Das --- .../bindings/cpufreq/cpufreq-qcom-hw.txt | 172 + 1 file changed, 172 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file mode 100644 index 000..90e396b --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt @@ -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: + Definition: must be "qcom,cpufreq-hw". + +- clocks + Usage: required + Value type: From common clock binding. + Definition: clock handle for XO clock and GPLL0 clock. + +- clock-names + Usage: required + Value type: From common clock binding. + Definition: must be "xo", "cpu_clk". + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the HW bases in + each frequency domain. +- reg-names + Usage: Optional + Value type: + 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
[PATCH v10 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
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 Signed-off-by: Taniya Das --- drivers/cpufreq/Kconfig.arm | 11 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 346 ++ 3 files changed, 358 insertions(+) create mode 100644 drivers/cpufreq/qcom-cpufreq-hw.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 4e1131e..688f102 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -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 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index d5ee456..789b2e0 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -62,6 +62,7 @@ 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_KRYO)+= qcom-cpufreq-kryo.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c new file mode 100644 index 000..6390e85 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#define LUT_MAX_ENTRIES40U +#define CORE_COUNT_VAL(val)(((val) & (GENMASK(18, 16))) >> 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 + +struct cpufreq_qcom { + struct cpufreq_frequency_table *table; + void __iomem *perf_base; + cpumask_t related_cpus; + unsigned int max_cores; + unsigned long xo_rate; + unsigned long cpu_hw_rate; +}; + +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; + +static int +qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, +unsigned int index) +{ + struct cpufreq_qcom *c = policy->driver_data; + + writel_relaxed(index, c->perf_base); + + return 0; +} + +static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) +{ + struct cpufreq_qcom *c; + struct cpufreq_policy *policy; + unsigned int index; + + policy = cpufreq_cpu_get_raw(cpu); + if (!policy) + return 0; + + c = policy->driver_data; + + index = readl_relaxed(c->perf_base); + 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) +{ + struct cpufreq_qcom *c = policy->driver_data; + int index; + + index = policy->cached_resolved_idx; + if (index < 0) + return 0; + + writel_relaxed(index, c->perf_base); + + return policy->freq_table[index].frequency; +} + +static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) +{ + struct cpufreq_qcom *c; + + c = qcom_freq_domain_map[policy->cpu]; + if (!c) { + pr_err("No scaling support for CPU%d\n", policy->cpu); + return -ENODEV; + } + + cpumask_copy(policy->cpus, &c->related_cpus); + + policy->fast_switch_possible = true; + policy->freq_table = c->table; + policy->driver_data = c; + + 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_STICK
[PATCH v10 0/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
[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 | 346 + 4 files changed, 530 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.
Re: [PATCH v9 2/2] clk: qcom: Add lpass clock controller driver for SDM845
Hello Stephen, On 11/22/2018 12:37 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-11-09 17:44:16) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index f133b7f..ba8ff99 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -3153,6 +3153,34 @@ enum { }, }; +static struct clk_branch gcc_lpass_q6_axi_clk = { + .halt_reg = 0x47000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_q6_axi_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_lpass_sway_clk = { + .halt_reg = 0x47008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_sway_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, .pd = { @@ -3453,6 +3481,8 @@ enum { [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr, [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr, [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr, + [GCC_LPASS_Q6_AXI_CLK] = &gcc_lpass_q6_axi_clk.clkr, + [GCC_LPASS_SWAY_CLK] = &gcc_lpass_sway_clk.clkr, Sigh, more coordination with sdm845 mtp problems here due to the clks being protected by firmware. I guess I can just merge this and the mtp dts bits will land in Andy's tree during the same merge window? Or I may need to take the dts bits for this into clk tree so that the broken time is only between two commits. }; static const struct qcom_reset_map gcc_sdm845_resets[] = { diff --git a/drivers/clk/qcom/lpasscc-sdm845.c b/drivers/clk/qcom/lpasscc-sdm845.c new file mode 100644 index 000..2ef7f2a --- /dev/null +++ b/drivers/clk/qcom/lpasscc-sdm845.c @@ -0,0 +1,192 @@ [...] + +static const struct of_device_id lpass_cc_sdm845_match_table[] = { + { .compatible = "qcom,sdm845-lpasscc" }, + { } +}; +MODULE_DEVICE_TABLE(of, lpass_cc_sdm845_match_table); Move this down to the before the driver structure please. Would do it in the next patch. + +static int lpass_cc_sdm845_probe(struct platform_device *pdev) +{ + const struct qcom_cc_desc *desc; + int ret; + + lpass_regmap_config.name = "cc"; + desc = &lpass_cc_sdm845_desc; + + ret = lpass_clocks_sdm845_probe(pdev, 0, desc); + if (ret) + return ret; + + lpass_regmap_config.name = "qdsp6ss"; + desc = &lpass_qdsp6ss_sdm845_desc; + + return lpass_clocks_sdm845_probe(pdev, 1, desc); +} + +static struct platform_driver lpass_cc_sdm845_driver = { + .probe = lpass_cc_sdm845_probe, + .driver = { + .name = "sdm845-lpasscc", + .of_match_table = lpass_cc_sdm845_match_table, + }, +}; + +static int __init lpass_cc_sdm845_init(void) +{ + return platform_driver_register(&lpass_cc_sdm845_driver); +} +subsys_initcall(lpass_cc_sdm845_init); + +static void __exit lpass_cc_sdm845_exit(void) +{ + platform_driver_unregister(&lpass_cc_sdm845_driver); +} +module_exit(lpass_cc_sdm845_exit); + +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION? Would add it in the next patch. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v9 1/2] dt-bindings: clock: Introduce QCOM LPASS clock bindings
Hello Rob, On 11/13/2018 5:49 AM, Rob Herring wrote: On Sat, Nov 10, 2018 at 07:14:15AM +0530, Taniya Das wrote: Add device tree bindings for Low Power Audio subsystem clock controller for Qualcomm Technology Inc's SDM845 SoCs. Signed-off-by: Taniya Das --- .../devicetree/bindings/clock/qcom,gcc.txt | 16 + Seems like a separate change? Sure, would spilt it in the next patch. .../devicetree/bindings/clock/qcom,lpasscc.txt | 26 ++ include/dt-bindings/clock/qcom,gcc-sdm845.h| 2 ++ include/dt-bindings/clock/qcom,lpass-sdm845.h | 16 + 4 files changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lpasscc.txt create mode 100644 include/dt-bindings/clock/qcom,lpass-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 52d9345..8661c3c 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -35,6 +35,8 @@ be part of GCC and hence the TSENS properties can also be part of the GCC/clock-controller node. For more details on the TSENS properties please refer Documentation/devicetree/bindings/thermal/qcom-tsens.txt +- protected-clocks : Protected clock specifier list as per common clock + binding. Example: clock-controller@90 { @@ -55,3 +57,17 @@ Example of GCC with TSENS properties: #reset-cells = <1>; #thermal-sensor-cells = <1>; }; + +Example of GCC with protected-clocks properties: + clock-controller@10 { + compatible = "qcom,gcc-sdm845"; + reg = <0x10 0x1f>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + protected-clocks = , + , + , + , + ; + }; diff --git a/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt new file mode 100644 index 000..b9e9787 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt @@ -0,0 +1,26 @@ +Qualcomm LPASS Clock Controller Binding +--- + +Required properties : +- compatible : shall contain "qcom,sdm845-lpasscc" +- #clock-cells : from common clock binding, shall contain 1. +- reg : shall contain base register address and size, + in the order + Index-0 maps to LPASS_CC register region + Index-1 maps to LPASS_QDSP6SS register region No input clocks? There are no input clocks required. + +Optional properties : +- reg-names: register names of LPASS domain +"cc", "qdsp6ss". + +Example: + +The below node has to be defined in the cases where the LPASS peripheral loader +would bring the subsystem out of reset. + + lpasscc: clock-controller@17014000 { + compatible = "qcom,sdm845-lpasscc"; + reg = <0x17014000 0x1f004>, <0x1730 0x200>; + reg-names = "cc", "qdsp6ss"; + #clock-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h index b8eae5a..968fa65 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h @@ -197,6 +197,8 @@ #define GCC_QSPI_CORE_CLK_SRC 187 #define GCC_QSPI_CORE_CLK 188 #define GCC_QSPI_CNOC_PERIPH_AHB_CLK 189 +#define GCC_LPASS_Q6_AXI_CLK 190 +#define GCC_LPASS_SWAY_CLK 191 /* GCC Resets */ #define GCC_MMSS_BCR 0 diff --git a/include/dt-bindings/clock/qcom,lpass-sdm845.h b/include/dt-bindings/clock/qcom,lpass-sdm845.h new file mode 100644 index 000..015968e --- /dev/null +++ b/include/dt-bindings/clock/qcom,lpass-sdm845.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H +#define _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H + +#define LPASS_AUDIO_WRAPPER_AON_CLK0 +#define LPASS_Q6SS_AHBM_AON_CLK1 +#define LPASS_Q6SS_AHBS_AON_CLK2 +#define LPASS_QDSP6SS_XO_CLK 3 +#define LPASS_QDSP6SS_SLEEP_CLK4 +#define LPASS_QDSP6SS_COR
[PATCH v10 2/3] dt-bindings: clock: Introduce QCOM LPASS clock bindings
Add device tree bindings for Low Power Audio subsystem clock controller for Qualcomm Technology Inc's SDM845 SoCs. Signed-off-by: Taniya Das --- .../devicetree/bindings/clock/qcom,gcc.txt | 4 +++- .../devicetree/bindings/clock/qcom,lpasscc.txt | 26 ++ include/dt-bindings/clock/qcom,gcc-sdm845.h| 2 ++ include/dt-bindings/clock/qcom,lpass-sdm845.h | 15 + 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lpasscc.txt create mode 100644 include/dt-bindings/clock/qcom,lpass-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 5e37de9..8661c3c 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -67,5 +67,7 @@ Example of GCC with protected-clocks properties: #power-domain-cells = <1>; protected-clocks = , , - ; + , + , + ; }; diff --git a/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt new file mode 100644 index 000..b9e9787 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt @@ -0,0 +1,26 @@ +Qualcomm LPASS Clock Controller Binding +--- + +Required properties : +- compatible : shall contain "qcom,sdm845-lpasscc" +- #clock-cells : from common clock binding, shall contain 1. +- reg : shall contain base register address and size, + in the order + Index-0 maps to LPASS_CC register region + Index-1 maps to LPASS_QDSP6SS register region + +Optional properties : +- reg-names: register names of LPASS domain +"cc", "qdsp6ss". + +Example: + +The below node has to be defined in the cases where the LPASS peripheral loader +would bring the subsystem out of reset. + + lpasscc: clock-controller@17014000 { + compatible = "qcom,sdm845-lpasscc"; + reg = <0x17014000 0x1f004>, <0x1730 0x200>; + reg-names = "cc", "qdsp6ss"; + #clock-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h index b8eae5a..968fa65 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h @@ -197,6 +197,8 @@ #define GCC_QSPI_CORE_CLK_SRC 187 #define GCC_QSPI_CORE_CLK 188 #define GCC_QSPI_CNOC_PERIPH_AHB_CLK 189 +#define GCC_LPASS_Q6_AXI_CLK 190 +#define GCC_LPASS_SWAY_CLK 191 /* GCC Resets */ #define GCC_MMSS_BCR 0 diff --git a/include/dt-bindings/clock/qcom,lpass-sdm845.h b/include/dt-bindings/clock/qcom,lpass-sdm845.h new file mode 100644 index 000..6590508 --- /dev/null +++ b/include/dt-bindings/clock/qcom,lpass-sdm845.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H +#define _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H + +#define LPASS_Q6SS_AHBM_AON_CLK0 +#define LPASS_Q6SS_AHBS_AON_CLK1 +#define LPASS_QDSP6SS_XO_CLK 2 +#define LPASS_QDSP6SS_SLEEP_CLK3 +#define LPASS_QDSP6SS_CORE_CLK 4 + +#endif -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v10 0/3] Add support for LPASS clock controller for SDM845
[v10] * Separate change to add protected-clocks list in GCC binding. * Remove the clock support 'LPASS_AUDIO_WRAPPER_AON_CLK' as it is always ON clock. * Add few comments for module description and match table. [v9] * Update GCC documentation binding with the protected-clocks list. * Update the GCC code to add the GCC lpass clocks. * This depends on the acceptance of https://lore.kernel.org/lkml/20181105194011.43770-1-swb...@chromium.org/ [v8] * Add CLK_IS_CRITICAL for GCC lpass clocks for lpass clocks access to go through always. [v7] * Cleanup header file inclusions. * Move the comments along with the flags. * Update the commit with details for CLK_IGNORE_UNUSED. [v6] * Update the logic to register the lpass clocks when the device tree property is not present. * Add the CLK_IGNORE_UNUSED flag for the lpass clocks to not gate the clocks at late_init. [v5] * Address the comments in device tree binding to update the reg-names, update the unit address in lpass clock node example and also add reg property for the gcc clock node. * Update the lpass driver to take care of the reg-names. [v4] * Update the description in GCC Documentation binding for 'qcom,lpass-protected'. * Remove 'qcom,lpass-protected' from LPASS Documentation binding. * Update KConfig to use Low Power Audio Subsystem. * Add module_exit() and also update return value for devm_ioremap_resource failure. [v3] * Add a device tree property to identify lpass protected GCC clocks. * Update the GCC driver code to register the lpass clocks when the flag is defined. * Add comment for clocks using the BRANCH_HALT_SKIP flag. * Use platform APIs instead of of_address_to_resource. * Replace devm_ioremap with devm_ioremap_resource. * Use fixed index for 'lpass_cc' & 'lpass_qdsp6ss' in probe. [v2] * Make gcc_lpass_sway_clk static. * Remove using child nodes and use reg-names to differentiate various domains of LPASS CC. Add support for the lpass clock controller found on SDM845 based devices. This would allow lpass peripheral loader drivers to control the clocks to bring the subsystem out of reset. Taniya Das (3): dt-bindings: clock: Update GCC bindings for protected-clocks dt-bindings: clock: Introduce QCOM LPASS clock bindings clk: qcom: Add lpass clock controller driver for SDM845 .../devicetree/bindings/clock/qcom,gcc.txt | 16 ++ .../devicetree/bindings/clock/qcom,lpasscc.txt | 26 +++ drivers/clk/qcom/Kconfig | 9 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sdm845.c | 30 drivers/clk/qcom/lpasscc-sdm845.c | 179 + include/dt-bindings/clock/qcom,gcc-sdm845.h| 2 + include/dt-bindings/clock/qcom,lpass-sdm845.h | 15 ++ 8 files changed, 278 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lpasscc.txt create mode 100644 drivers/clk/qcom/lpasscc-sdm845.c create mode 100644 include/dt-bindings/clock/qcom,lpass-sdm845.h -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v10 1/3] dt-bindings: clock: Update GCC bindings for protected-clocks
Add protected-clocks list which could used to specify the clocks to be bypassed on certain devices. Signed-off-by: Taniya Das --- Documentation/devicetree/bindings/clock/qcom,gcc.txt | 14 ++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 52d9345..5e37de9 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -35,6 +35,8 @@ be part of GCC and hence the TSENS properties can also be part of the GCC/clock-controller node. For more details on the TSENS properties please refer Documentation/devicetree/bindings/thermal/qcom-tsens.txt +- protected-clocks : Protected clock specifier list as per common clock + binding. Example: clock-controller@90 { @@ -55,3 +57,15 @@ Example of GCC with TSENS properties: #reset-cells = <1>; #thermal-sensor-cells = <1>; }; + +Example of GCC with protected-clocks properties: + clock-controller@10 { + compatible = "qcom,gcc-sdm845"; + reg = <0x10 0x1f>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + protected-clocks = , + , + ; + }; -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v10 3/3] clk: qcom: Add lpass clock controller driver for SDM845
Add support for the lpass clock controller found on SDM845 based devices. This would allow lpass peripheral loader drivers to control the clocks to bring the subsystem out of reset. LPASS clocks present on the global clock controller would be registered with the clock framework based on the protected-clock flag. Also do not gate these clocks if they are left unused, as the lpass clocks require the global clock controller lpass clocks to be enabled before they are accessed. Mark the GCC lpass clocks as CRITICAL, for the LPASS clock access. Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 9 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sdm845.c | 30 +++ drivers/clk/qcom/lpasscc-sdm845.c | 179 ++ 4 files changed, 219 insertions(+) create mode 100644 drivers/clk/qcom/lpasscc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index a611531..23adc4c 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -293,6 +293,15 @@ config SDM_DISPCC_845 Say Y if you want to support display devices and functionality such as splash screen. +config SDM_LPASSCC_845 + tristate "SDM845 Low Power Audio Subsystem (LPAAS) Clock Controller" + depends on COMMON_CLK_QCOM + select SDM_GCC_845 + help + Support for the LPASS clock controller on SDM845 devices. + Say Y if you want to use the LPASS branch clocks of the LPASS clock + controller to reset the LPASS subsystem. + config SPMI_PMIC_CLKDIV tristate "SPMI PMIC clkdiv Support" depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 981882e..3d530b1 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o +obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index f133b7f..ba8ff99 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -3153,6 +3153,34 @@ enum { }, }; +static struct clk_branch gcc_lpass_q6_axi_clk = { + .halt_reg = 0x47000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_q6_axi_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_lpass_sway_clk = { + .halt_reg = 0x47008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_sway_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, .pd = { @@ -3453,6 +3481,8 @@ enum { [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr, [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr, [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr, + [GCC_LPASS_Q6_AXI_CLK] = &gcc_lpass_q6_axi_clk.clkr, + [GCC_LPASS_SWAY_CLK] = &gcc_lpass_sway_clk.clkr, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { diff --git a/drivers/clk/qcom/lpasscc-sdm845.c b/drivers/clk/qcom/lpasscc-sdm845.c new file mode 100644 index 000..9c63542 --- /dev/null +++ b/drivers/clk/qcom/lpasscc-sdm845.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include + +#include "clk-regmap.h" +#include "clk-branch.h" +#include "common.h" + +static struct clk_branch lpass_q6ss_ahbm_aon_clk = { + .halt_reg = 0x12000, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x12000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_q6ss_ahbm_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch lpass_q6ss_ahbs_aon_clk = { + .halt_reg = 0x1f000, + .halt_check = BRANCH_VOTED, + .clkr
Re: [PATCH v3 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC
Hello Stephen, On 11/5/2018 12:04 PM, Stephen Boyd wrote: Quoting Amit Nischal (2018-08-12 23:33:04) For some of the GDSCs, there is a requirement to enable/disable the few clocks before turning on/off the gdsc power domain. Add support for the same by specifying a list of clk_hw pointers per gdsc and enable/disable them along with power domain on/off callbacks. Signed-off-by: Amit Nischal In v1 of this patch series I asked for much more information in this commit text. Please add it here. I won't apply this patch until the justification is put into this commit text. Would surely add more details. --- drivers/clk/qcom/gdsc.c | 44 drivers/clk/qcom/gdsc.h | 5 + 2 files changed, 49 insertions(+) diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index a077133..b6adca1 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -12,6 +12,8 @@ */ #include +#include +#include This makes me unhappy. It's almost always a problem when we see clk.h and clk-provider.h included in the same file, so if gdsc has to call clk APIs to operate correctly, then we should do that by having the gdsc code get clks properly instead of directly reaching into the clk_hw structure to get a clk pointer. This means we should have the gdsc code ask the clk framework to convert a clk_hw pointer into a clk pointer because of how so intimately connected the gdsc is to clks on this SoC. But given all that, I'm still trying to understand why we need to do this within the gdsc code. Adding these clk calls to the gdsc seems like we're attaching at the wrong abstraction level. Especially if the reason we do it is to make it easier for the GPU driver to handle dependencies. I hope that's not the case. Either way, it would make more sense to me if we made genpds for the clks and genpds for the gdscs and then associated the clk genpds with the gdsc genpds so that when a gdsc is enabled the clk domain that it depends on is enabled first. Then we have a generic solution for connecting clks to gdscs that doesn't require us to add more logic to the gdsc driver and avoids having clk providers do clk consumer things. Instead, it's all handled outside of this driver by specifying a domain dependency. It may turn out that such a solution would still need a way to make clk domains in the clk driver, and it will probably need to do that by converting clk_hw structures into clk pointers, but it would be good to do that anyway. So in summary, I believe we should end up at a point where we have clk domains and power domains (gdscs) all supported with genpds, and then we can connect them together however they're connected by linking the genpds to each other. Device drivers wouldn't really need to care how they're connected, as long as those genpds are attached to their device then the driver would be able to enable/disable them through runtime PM. But I can see how this may be hard to do for this patch series, so in the spirit of progress and getting things done, it would be OK with me if the gdsc code called some new clk API to convert a clk_hw pointer into a clk pointer and then did the same enable/disable things it's doing in this patch. This whole patch would need to be completely untangled and ripped out later when we have clk domains but at least we could get something working now while we work on making clk domains and plumbing them into genpds and runtime PM. Yes, I agree with your points above, but as genpds currently cannot have a way to take in clock handles, this was the way we chose. I would add a new clock API as suggested and submit the next series. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v3 4/4] clk: qcom: Add graphics clock controller driver for SDM845
Hello Stephen, On 11/5/2018 12:07 PM, Stephen Boyd wrote: Quoting Amit Nischal (2018-08-12 23:33:07) + +static int gpu_cc_sdm845_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + unsigned int value, mask; + int ret; + + regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + /* +* Configure gpu_cc_cx_gmu_clk with recommended +* wakeup/sleep settings +*/ + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; + value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT; + regmap_update_bits(regmap, 0x1098, mask, value); + + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap); + if (ret) + return ret; + + /* Configure clk_dis_wait for gpu_cx_gdsc */ + regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK, + 8 << CLK_DIS_WAIT_SHIFT); Is there a reason this is done after clks are registered? I'd think we would want to do it before. Yes, it could be done before, would move it. + + /* Set supported range of frequencies for gfx3d clock */ + clk_hw_set_rate_range(&gpu_cc_gx_gfx3d_clk_src.clkr.hw, 18000, + 71000); + + return 0; +} -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v11 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
Hello Stephen, Viresh Thanks for the code and suggestions. Having a NR_DOMAINS '2' makes the driver not scalable for re-use. This assumption is only true for the current version of the HW and do not intend to update/clean-up this logic again. So want to stick keeping current logic of having the *qcom_freq_domain_map[NR_CPUS]. On 12/5/2018 4:35 AM, Stephen Boyd wrote: Quoting Stephen Boyd (2018-12-04 14:28:11) Quoting Viresh Kumar (2018-12-03 21:12:31) Hi Taniya, Sorry that I haven't been reviewing it much from last few iterations as I was letting others get this into a better shape. Thanks for your efforts.. On 02-12-18, 09:25, Taniya Das wrote: +++ b/drivers/cpufreq/qcom-cpufreq-hw.c +struct cpufreq_qcom { + struct cpufreq_frequency_table *table; + void __iomem *perf_state_reg; + cpumask_t related_cpus; +}; + +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; Now that the code is much more simplified, I am not sure if you need this per-cpu structure at all. The only place where you are using it is in qcom_cpufreq_hw_cpu_init() and probe(). Why not merge qcom_cpu_resources_init() completely into qcom_cpufreq_hw_cpu_init() and get rid of this structure entirely ? Good point. Here's an untested patch to handle that. It removes the related functionality and makes an array of pointers to the domains that are created each time qcom_cpu_resources_init() is called. ---8< diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c index 8dc6b73c2f22..04e7cfd70316 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -23,14 +23,14 @@ #define REG_LUT_TABLE 0x110 #define REG_PERF_STATE 0x920 +#define MAX_FREQ_DOMAINS 2 + struct cpufreq_qcom { struct cpufreq_frequency_table *table; void __iomem *perf_state_reg; cpumask_t related_cpus; }; -static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; - static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, unsigned int index) { @@ -76,9 +76,14 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) { + struct cpufreq_qcom **freq_domain_map; struct cpufreq_qcom *c; - c = qcom_freq_domain_map[policy->cpu]; + freq_domain_map = cpufreq_get_driver_data(); + if (!freq_domain_map) + return -ENODEV; + + c = freq_domain_map[policy->cpu]; And this fails now because it indexes based on cpu number. We have to parse the frequency domain out of the cpunode again to fix that. Here's the updated (still untested) patch and I also just allocated the freq domain array up front instead of in each domain init routine to simplify some more. diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c index 8dc6b73c2f22..bc0d734f7e3c 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -23,14 +23,14 @@ #define REG_LUT_TABLE 0x110 #define REG_PERF_STATE0x920 +#define MAX_FREQ_DOMAINS 2 + struct cpufreq_qcom { struct cpufreq_frequency_table *table; void __iomem *perf_state_reg; cpumask_t related_cpus; }; -static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; - static int qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, unsigned int index) { @@ -76,9 +76,26 @@ static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) { - struct cpufreq_qcom *c; + struct cpufreq_qcom *freq_domain_map, *c; + struct device_node *cpu_np; + struct of_phandle_args args; + int ret; + + freq_domain_map = cpufreq_get_driver_data(); + if (!freq_domain_map) + return -ENODEV; + + cpu_np = of_cpu_device_node_get(policy->cpu); + if (!cpu_np) + return -ENODEV; + + 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; - c = qcom_freq_domain_map[policy->cpu]; + c = &freq_domain_map[args.args[0]]; if (!c) { pr_err("No scaling support for CPU%d\n", policy->cpu); return -ENODEV; @@ -171,43 +188,15 @@ static int qcom_cpufreq_hw_read_lut(struct device *dev, struct cpufreq_qcom *c, return 0; } -static void qcom_get_related_cpus(int index, struct cpumask *m) -{ - struct device_node *cpu_np; - struct of_phandle_args args; -
[PATCH] arm64: dts: sdm845: Add lpasscc node
This adds the low pass audio clock controller node to sdm845 based on the example in the bindings. Signed-off-by: Taniya Das --- arch/arm64/boot/dts/qcom/sdm845-mtp.dts | 4 +++- arch/arm64/boot/dts/qcom/sdm845.dtsi| 8 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts index b3def03..cf73f3c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts @@ -346,7 +346,9 @@ &gcc { protected-clocks = , , - ; + , + , + ; }; &i2c10 { diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 1419b00..a3db089 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -1264,6 +1265,13 @@ #power-domain-cells = <1>; }; + lpasscc: clock-controller@17014000 { + compatible = "qcom,sdm845-lpasscc"; + reg = <0x17014000 0x1f004>, <0x1730 0x200>; + reg-names = "cc", "qdsp6ss"; + #clock-cells = <1>; + }; + tsens0: thermal-sensor@c263000 { compatible = "qcom,sdm845-tsens", "qcom,tsens-v2"; reg = <0xc263000 0x1ff>, /* TM */ -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH] clk: qcom: Remove LPASS_CC config for GCC lpass clocks
The GCC lpass clocks are updated as protected, so clean up the ifdefers. Signed-off-by: Taniya Das --- drivers/clk/qcom/gcc-sdm845.c | 5 - 1 file changed, 5 deletions(-) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index c782e62..ba8ff99 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -3153,8 +3153,6 @@ enum { }, }; -/* TODO: Remove after DTS updated to protect these */ -#ifdef CONFIG_SDM_LPASSCC_845 static struct clk_branch gcc_lpass_q6_axi_clk = { .halt_reg = 0x47000, .halt_check = BRANCH_HALT, @@ -3182,7 +3180,6 @@ enum { }, }, }; -#endif static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, @@ -3484,10 +3481,8 @@ enum { [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr, [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr, [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr, -#ifdef CONFIG_SDM_LPASSCC_845 [GCC_LPASS_Q6_AXI_CLK] = &gcc_lpass_q6_axi_clk.clkr, [GCC_LPASS_SWAY_CLK] = &gcc_lpass_sway_clk.clkr, -#endif }; static const struct qcom_reset_map gcc_sdm845_resets[] = { -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Re: [PATCH v10 3/3] clk: qcom: Add lpass clock controller driver for SDM845
Hello Stephen, On 11/27/2018 2:44 PM, Stephen Boyd wrote: Quoting Taniya Das (2018-11-21 23:53:41) + +static struct clk_branch lpass_qdsp6ss_core_clk = { + .halt_reg = 0x20, + /* CLK_OFF would not toggle until LPASS is not out of reset */ Is this really "CLK_OFF won't toggle until LPASS it out of reset"? Would take care of it, in the next series. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v10 3/3] clk: qcom: Add lpass clock controller driver for SDM845
Hello Stephen, On 11/29/2018 2:40 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-11-21 23:53:41) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index f133b7f..ba8ff99 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -3153,6 +3153,34 @@ enum { }, }; +static struct clk_branch gcc_lpass_q6_axi_clk = { + .halt_reg = 0x47000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_q6_axi_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_lpass_sway_clk = { + .halt_reg = 0x47008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_sway_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, .pd = { @@ -3453,6 +3481,8 @@ enum { [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr, [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr, [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr, + [GCC_LPASS_Q6_AXI_CLK] = &gcc_lpass_q6_axi_clk.clkr, + [GCC_LPASS_SWAY_CLK] = &gcc_lpass_sway_clk.clkr, I have one single idea to avoid the integration nightmare with dts needing another update for this on platforms where these can't be touched. It's not perfect, but we can throw these clks and usage of the clks behind an #ifdef CONFIG_SDM_LPASSCC_845 and then let the dts parts match up with the clk driver parts in linux-next. After everything is merged together, someone can turn on the knobs for LPASS clk controller and make sure they have the right dts bits to mark them as protected. Sure, would keep it under the ifdefer and would clean it up later. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v11 0/3] Add support for LPASS clock controller for SDM845
[v11] * Add the GCC LPASS clocks only if LPASSCC config is present. * Update the comment in lpasscc driver. [v10] * Separate change to add protected-clocks list in GCC binding. * Remove the clock support 'LPASS_AUDIO_WRAPPER_AON_CLK' as it is always ON clock. * Add few comments for module description and match table. [v9] * Update GCC documentation binding with the protected-clocks list. * Update the GCC code to add the GCC lpass clocks. * This depends on the acceptance of https://lore.kernel.org/lkml/20181105194011.43770-1-swb...@chromium.org/ [v8] * Add CLK_IS_CRITICAL for GCC lpass clocks for lpass clocks access to go through always. [v7] * Cleanup header file inclusions. * Move the comments along with the flags. * Update the commit with details for CLK_IGNORE_UNUSED. [v6] * Update the logic to register the lpass clocks when the device tree property is not present. * Add the CLK_IGNORE_UNUSED flag for the lpass clocks to not gate the clocks at late_init. [v5] * Address the comments in device tree binding to update the reg-names, update the unit address in lpass clock node example and also add reg property for the gcc clock node. * Update the lpass driver to take care of the reg-names. [v4] * Update the description in GCC Documentation binding for 'qcom,lpass-protected'. * Remove 'qcom,lpass-protected' from LPASS Documentation binding. * Update KConfig to use Low Power Audio Subsystem. * Add module_exit() and also update return value for devm_ioremap_resource failure. [v3] * Add a device tree property to identify lpass protected GCC clocks. * Update the GCC driver code to register the lpass clocks when the flag is defined. * Add comment for clocks using the BRANCH_HALT_SKIP flag. * Use platform APIs instead of of_address_to_resource. * Replace devm_ioremap with devm_ioremap_resource. * Use fixed index for 'lpass_cc' & 'lpass_qdsp6ss' in probe. [v2] * Make gcc_lpass_sway_clk static. * Remove using child nodes and use reg-names to differentiate various domains of LPASS CC. Add support for the lpass clock controller found on SDM845 based devices. This would allow lpass peripheral loader drivers to control the clocks to bring the subsystem out of reset. Taniya Das (3): dt-bindings: clock: Update GCC bindings for protected-clocks dt-bindings: clock: Introduce QCOM LPASS clock bindings clk: qcom: Add lpass clock controller driver for SDM845 .../devicetree/bindings/clock/qcom,gcc.txt | 16 ++ .../devicetree/bindings/clock/qcom,lpasscc.txt | 26 +++ drivers/clk/qcom/Kconfig | 9 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sdm845.c | 32 drivers/clk/qcom/lpasscc-sdm845.c | 179 + include/dt-bindings/clock/qcom,gcc-sdm845.h| 2 + include/dt-bindings/clock/qcom,lpass-sdm845.h | 15 ++ 8 files changed, 280 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lpasscc.txt create mode 100644 drivers/clk/qcom/lpasscc-sdm845.c create mode 100644 include/dt-bindings/clock/qcom,lpass-sdm845.h -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v11 2/3] dt-bindings: clock: Introduce QCOM LPASS clock bindings
Add device tree bindings for Low Power Audio subsystem clock controller for Qualcomm Technology Inc's SDM845 SoCs. Reviewed-by: Rob Herring Signed-off-by: Taniya Das --- .../devicetree/bindings/clock/qcom,gcc.txt | 4 +++- .../devicetree/bindings/clock/qcom,lpasscc.txt | 26 ++ include/dt-bindings/clock/qcom,gcc-sdm845.h| 2 ++ include/dt-bindings/clock/qcom,lpass-sdm845.h | 15 + 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lpasscc.txt create mode 100644 include/dt-bindings/clock/qcom,lpass-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 5e37de9..8661c3c 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -67,5 +67,7 @@ Example of GCC with protected-clocks properties: #power-domain-cells = <1>; protected-clocks = , , - ; + , + , + ; }; diff --git a/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt new file mode 100644 index 000..b9e9787 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt @@ -0,0 +1,26 @@ +Qualcomm LPASS Clock Controller Binding +--- + +Required properties : +- compatible : shall contain "qcom,sdm845-lpasscc" +- #clock-cells : from common clock binding, shall contain 1. +- reg : shall contain base register address and size, + in the order + Index-0 maps to LPASS_CC register region + Index-1 maps to LPASS_QDSP6SS register region + +Optional properties : +- reg-names: register names of LPASS domain +"cc", "qdsp6ss". + +Example: + +The below node has to be defined in the cases where the LPASS peripheral loader +would bring the subsystem out of reset. + + lpasscc: clock-controller@17014000 { + compatible = "qcom,sdm845-lpasscc"; + reg = <0x17014000 0x1f004>, <0x1730 0x200>; + reg-names = "cc", "qdsp6ss"; + #clock-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h index b8eae5a..968fa65 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h @@ -197,6 +197,8 @@ #define GCC_QSPI_CORE_CLK_SRC 187 #define GCC_QSPI_CORE_CLK 188 #define GCC_QSPI_CNOC_PERIPH_AHB_CLK 189 +#define GCC_LPASS_Q6_AXI_CLK 190 +#define GCC_LPASS_SWAY_CLK 191 /* GCC Resets */ #define GCC_MMSS_BCR 0 diff --git a/include/dt-bindings/clock/qcom,lpass-sdm845.h b/include/dt-bindings/clock/qcom,lpass-sdm845.h new file mode 100644 index 000..6590508 --- /dev/null +++ b/include/dt-bindings/clock/qcom,lpass-sdm845.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H +#define _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H + +#define LPASS_Q6SS_AHBM_AON_CLK0 +#define LPASS_Q6SS_AHBS_AON_CLK1 +#define LPASS_QDSP6SS_XO_CLK 2 +#define LPASS_QDSP6SS_SLEEP_CLK3 +#define LPASS_QDSP6SS_CORE_CLK 4 + +#endif -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v11 3/3] clk: qcom: Add lpass clock controller driver for SDM845
Add support for the lpass clock controller found on SDM845 based devices. This would allow lpass peripheral loader drivers to control the clocks to bring the subsystem out of reset. LPASS clocks present on the global clock controller would be registered with the clock framework based on the protected-clock flag. Also do not gate these clocks if they are left unused, as the lpass clocks require the global clock controller lpass clocks to be enabled before they are accessed. Mark the GCC lpass clocks as CRITICAL, for the LPASS clock access. Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 9 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sdm845.c | 32 +++ drivers/clk/qcom/lpasscc-sdm845.c | 179 ++ 4 files changed, 221 insertions(+) create mode 100644 drivers/clk/qcom/lpasscc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 6f3e466..d87a22e 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -302,6 +302,15 @@ config SDM_DISPCC_845 Say Y if you want to support display devices and functionality such as splash screen. +config SDM_LPASSCC_845 + tristate "SDM845 Low Power Audio Subsystem (LPAAS) Clock Controller" + depends on COMMON_CLK_QCOM + select SDM_GCC_845 + help + Support for the LPASS clock controller on SDM845 devices. + Say Y if you want to use the LPASS branch clocks of the LPASS clock + controller to reset the LPASS subsystem. + config SPMI_PMIC_CLKDIV tristate "SPMI PMIC clkdiv Support" depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 6ed2827..ee8d069 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o +obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index f133b7f..db90f9b 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -3153,6 +3153,34 @@ enum { }, }; +static struct clk_branch gcc_lpass_q6_axi_clk = { + .halt_reg = 0x47000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_q6_axi_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_lpass_sway_clk = { + .halt_reg = 0x47008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_sway_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, .pd = { @@ -3453,6 +3481,10 @@ enum { [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr, [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr, [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr, +#ifdef CONFIG_SDM_LPASSCC_845 + [GCC_LPASS_Q6_AXI_CLK] = &gcc_lpass_q6_axi_clk.clkr, + [GCC_LPASS_SWAY_CLK] = &gcc_lpass_sway_clk.clkr, +#endif }; static const struct qcom_reset_map gcc_sdm845_resets[] = { diff --git a/drivers/clk/qcom/lpasscc-sdm845.c b/drivers/clk/qcom/lpasscc-sdm845.c new file mode 100644 index 000..e246b99 --- /dev/null +++ b/drivers/clk/qcom/lpasscc-sdm845.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include + +#include "clk-regmap.h" +#include "clk-branch.h" +#include "common.h" + +static struct clk_branch lpass_q6ss_ahbm_aon_clk = { + .halt_reg = 0x12000, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x12000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_q6ss_ahbm_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch lpass_q6ss_ahbs_aon_clk = { + .halt_reg = 0x1f00
[PATCH v11 1/3] dt-bindings: clock: Update GCC bindings for protected-clocks
Add protected-clocks list which could used to specify the clocks to be bypassed on certain devices. Reviewed-by: Rob Herring Signed-off-by: Taniya Das --- Documentation/devicetree/bindings/clock/qcom,gcc.txt | 14 ++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 52d9345..5e37de9 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -35,6 +35,8 @@ be part of GCC and hence the TSENS properties can also be part of the GCC/clock-controller node. For more details on the TSENS properties please refer Documentation/devicetree/bindings/thermal/qcom-tsens.txt +- protected-clocks : Protected clock specifier list as per common clock + binding. Example: clock-controller@90 { @@ -55,3 +57,15 @@ Example of GCC with TSENS properties: #reset-cells = <1>; #thermal-sensor-cells = <1>; }; + +Example of GCC with protected-clocks properties: + clock-controller@10 { + compatible = "qcom,gcc-sdm845"; + reg = <0x10 0x1f>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + protected-clocks = , + , + ; + }; -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Re: [PATCH v10 1/2] dt-bindings: cpufreq: Introduce QCOM CPUFREQ Firmware bindings
Hello Rob, On 11/27/2018 12:28 AM, Rob Herring wrote: On Wed, Nov 21, 2018 at 10:02:36AM -0800, Matthias Kaehlcke wrote: On Wed, Nov 21, 2018 at 04:12:46PM +0530, Taniya Das wrote: 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 --- .../bindings/cpufreq/cpufreq-qcom-hw.txt | 172 + 1 file changed, 172 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file mode 100644 index 000..90e396b --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt @@ -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: + Definition: must be "qcom,cpufreq-hw". + +- clocks + Usage: required + Value type: From common clock binding. + Definition: clock handle for XO clock and GPLL0 clock. + +- clock-names + Usage: required + Value type: From common clock binding. + Definition: must be "xo", "cpu_clk". + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the HW bases in + each frequency domain. +- reg-names + Usage: Optional + Value type: + 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 { +
Re: [PATCH v10 1/2] dt-bindings: cpufreq: Introduce QCOM CPUFREQ Firmware bindings
Hello Matthias, On 11/21/2018 11:32 PM, Matthias Kaehlcke wrote: On Wed, Nov 21, 2018 at 04:12:46PM +0530, Taniya Das wrote: 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 --- .../bindings/cpufreq/cpufreq-qcom-hw.txt | 172 + 1 file changed, 172 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file mode 100644 index 000..90e396b --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt @@ -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: + Definition: must be "qcom,cpufreq-hw". + +- clocks + Usage: required + Value type: From common clock binding. + Definition: clock handle for XO clock and GPLL0 clock. + +- clock-names + Usage: required + Value type: From common clock binding. + Definition: must be "xo", "cpu_clk". + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the HW bases in + each frequency domain. +- reg-names + Usage: Optional + Value type: + 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";
Re: [PATCH v10 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
Hello Matthias, On 11/22/2018 12:11 AM, Matthias Kaehlcke wrote: Hi Taniya, thanks for respinning, a few nits inline. On Wed, Nov 21, 2018 at 04:12:47PM +0530, Taniya Das wrote: 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 Signed-off-by: Taniya Das --- drivers/cpufreq/Kconfig.arm | 11 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 346 ++ 3 files changed, 358 insertions(+) create mode 100644 drivers/cpufreq/qcom-cpufreq-hw.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 4e1131e..688f102 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -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 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index d5ee456..789b2e0 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -62,6 +62,7 @@ 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_KRYO) += qcom-cpufreq-kryo.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c new file mode 100644 index 000..6390e85 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#define LUT_MAX_ENTRIES40U +#define CORE_COUNT_VAL(val)(((val) & (GENMASK(18, 16))) >> 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 + +struct cpufreq_qcom { + struct cpufreq_frequency_table *table; + void __iomem *perf_base; nit: is this really a base address? It's the address of the perf state register, right? Better name it 'perf_state_reg'/'reg_perf_state' or similar (just 'perf_state' might be confusing, I'd expect a variable with this name to hold a state, not an address). I have updated the name to "perf_state_reg". + cpumask_t related_cpus; + unsigned int max_cores; + unsigned long xo_rate; + unsigned long cpu_hw_rate; +}; + +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; + +static int +qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, +unsigned int index) +{ + struct cpufreq_qcom *c = policy->driver_data; + + writel_relaxed(index, c->perf_base); + + return 0; +} + +static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) +{ + struct cpufreq_qcom *c; + struct cpufreq_policy *policy; + unsigned int index; + + policy = cpufreq_cpu_get_raw(cpu); + if (!policy) + return 0; + + c = policy->driver_data; + + index = readl_relaxed(c->perf_base); + 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) +{ + struct cpufreq_qcom *c = policy->driver_data; + int index; + + index = policy->cached_resolved_idx; + if (index < 0) + return 0; + + writel_relaxed(index, c->perf_base); + + return policy->freq_table[index].frequency; +} + +static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) +{ + struct cpufreq_qcom *c; + + c = qcom_freq_domain_map[policy->cpu]; + if (!c) { + pr_err("No scaling support for CPU%d\n&quo
Re: [PATCH v10 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
Hello Stephen, Thanks for the patch, I have updated the latest series with the patch and few comments from Matthias. On 11/21/2018 11:53 PM, Stephen Boyd wrote: Quoting Taniya Das (2018-11-21 02:42:47) diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index d5ee456..789b2e0 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -62,6 +62,7 @@ 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_KRYO)+= qcom-cpufreq-kryo.o +obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o This isn't alphabetically sorted. obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c new file mode 100644 index 000..6390e85 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#define LUT_MAX_ENTRIES40U +#define CORE_COUNT_VAL(val)(((val) & (GENMASK(18, 16))) >> 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 + +struct cpufreq_qcom { + struct cpufreq_frequency_table *table; + void __iomem *perf_base; + cpumask_t related_cpus; + unsigned int max_cores; + unsigned long xo_rate; + unsigned long cpu_hw_rate; +}; + +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; + +static int +qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, +unsigned int index) +{ + struct cpufreq_qcom *c = policy->driver_data; + + writel_relaxed(index, c->perf_base); + This isn't using the pointer directly though. + return 0; +} + +static unsigned int qcom_cpufreq_hw_get(unsigned int cpu) +{ + struct cpufreq_qcom *c; + struct cpufreq_policy *policy; + unsigned int index; + + policy = cpufreq_cpu_get_raw(cpu); + if (!policy) + return 0; + + c = policy->driver_data; + + index = readl_relaxed(c->perf_base); + 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) +{ + struct cpufreq_qcom *c = policy->driver_data; + int index; + + index = policy->cached_resolved_idx; + if (index < 0) + return 0; + + writel_relaxed(index, c->perf_base); + + return policy->freq_table[index].frequency; +} + +static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy) +{ + struct cpufreq_qcom *c; + + c = qcom_freq_domain_map[policy->cpu]; + if (!c) { + pr_err("No scaling support for CPU%d\n", policy->cpu); + return -ENODEV; + } + + cpumask_copy(policy->cpus, &c->related_cpus); + + policy->fast_switch_possible = true; + policy->freq_table = c->table; + policy->driver_data = c; + + 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, + .fast_switch= qcom_cpufreq_hw_fast_switch, + .name = "qcom-cpufreq-hw", + .attr = qcom_cpufreq_hw_attr, + .boost_enabled = true, +}; + +static int qcom_cpufreq_hw_read_lut(struct platform_device *pdev, + struct cpufreq_qcom *c, void __iomem *base) +{ + struct device *dev = &pdev->dev; + u32 data, src, lval, i, core_count, prev_cc, prev_freq, cur_freq; + + c->table = devm_kcalloc(dev, LUT_MAX_ENTRIES + 1, + sizeof(*c->table), GFP_KERNEL); + if (!c->table) + return -ENOMEM; + + for (i = 0; i < LUT_MAX_ENTRIES; i
[PATCH v11 0/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW
[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 | 334 + 4 files changed, 518 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 v11 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. Signed-off-by: Taniya Das --- .../bindings/cpufreq/cpufreq-qcom-hw.txt | 172 + 1 file changed, 172 insertions(+) create mode 100644 Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt new file mode 100644 index 000..2b82965 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.txt @@ -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: + Definition: must be "qcom,cpufreq-hw". + +- clocks + Usage: required + Value type: From common clock binding. + Definition: clock handle for XO clock and GPLL0 clock. + +- clock-names + Usage: required + Value type: From common clock binding. + Definition: must be "xo", "alternate". + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the HW bases in + each frequency domain. +- reg-names + Usage: Optional + Value type: + 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>; + }; +
[PATCH v11 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
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 Signed-off-by: Stephen Boyd Signed-off-by: Taniya Das --- drivers/cpufreq/Kconfig.arm | 11 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/qcom-cpufreq-hw.c | 334 ++ 3 files changed, 346 insertions(+) create mode 100644 drivers/cpufreq/qcom-cpufreq-hw.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 4e1131e..688f102 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -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 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index d5ee456..08c071b 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -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 diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c new file mode 100644 index 000..8dc6b73 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define LUT_MAX_ENTRIES40U +#define LUT_SRCGENMASK(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 + +struct cpufreq_qcom { + struct cpufreq_frequency_table *table; + void __iomem *perf_state_reg; + cpumask_t related_cpus; +}; + +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; + +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_cpu_init(struct cpufreq_policy *policy) +{ + struct cpufreq_qcom *c; + + c = qcom_freq_domain_map[policy->cpu]; + if (!c) { + pr_err("No scaling support for CPU%d\n", policy->cpu); + return -ENODEV; + } + + cpumask_copy(policy->cpus, &c->related_cpus); + + policy->fast_switch_possible = true; + policy->freq_table = c->table; + policy->driver_data = c->perf_state_reg; + + return 0; +} + +static struct freq_attr *qcom_cpufreq_hw_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + &cpufreq_freq_attr_scaling_boost_freqs, + NU
Re: [PATCH v11 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
Hello Viresh, On 12/4/2018 10:42 AM, Viresh Kumar wrote: Hi Taniya, Sorry that I haven't been reviewing it much from last few iterations as I was letting others get this into a better shape. Thanks for your efforts.. On 02-12-18, 09:25, Taniya Das wrote: +++ b/drivers/cpufreq/qcom-cpufreq-hw.c +struct cpufreq_qcom { + struct cpufreq_frequency_table *table; + void __iomem *perf_state_reg; + cpumask_t related_cpus; +}; + +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; Now that the code is much more simplified, I am not sure if you need this per-cpu structure at all. The only place where you are using it is in qcom_cpufreq_hw_cpu_init() and probe(). Why not merge qcom_cpu_resources_init() completely into qcom_cpufreq_hw_cpu_init() and get rid of this structure entirely ? Yes, we still would require the per-cpu. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v9 2/2] clk: qcom: Add lpass clock controller driver for SDM845
Add support for the lpass clock controller found on SDM845 based devices. This would allow lpass peripheral loader drivers to control the clocks to bring the subsystem out of reset. LPASS clocks present on the global clock controller would be registered with the clock framework based on the protected-clock flag. Also do not gate these clocks if they are left unused, as the lpass clocks require the global clock controller lpass clocks to be enabled before they are accessed. Mark the GCC lpass clocks as CRITICAL, for the LPASS clock access. Signed-off-by: Taniya Das --- drivers/clk/qcom/Kconfig | 9 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sdm845.c | 30 ++ drivers/clk/qcom/lpasscc-sdm845.c | 192 ++ 4 files changed, 232 insertions(+) create mode 100644 drivers/clk/qcom/lpasscc-sdm845.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index a611531..23adc4c 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -293,6 +293,15 @@ config SDM_DISPCC_845 Say Y if you want to support display devices and functionality such as splash screen. +config SDM_LPASSCC_845 + tristate "SDM845 Low Power Audio Subsystem (LPAAS) Clock Controller" + depends on COMMON_CLK_QCOM + select SDM_GCC_845 + help + Support for the LPASS clock controller on SDM845 devices. + Say Y if you want to use the LPASS branch clocks of the LPASS clock + controller to reset the LPASS subsystem. + config SPMI_PMIC_CLKDIV tristate "SPMI PMIC clkdiv Support" depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 981882e..3d530b1 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o +obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index f133b7f..ba8ff99 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -3153,6 +3153,34 @@ enum { }, }; +static struct clk_branch gcc_lpass_q6_axi_clk = { + .halt_reg = 0x47000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_q6_axi_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_lpass_sway_clk = { + .halt_reg = 0x47008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_lpass_sway_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, .pd = { @@ -3453,6 +3481,8 @@ enum { [GCC_QSPI_CORE_CLK_SRC] = &gcc_qspi_core_clk_src.clkr, [GCC_QSPI_CORE_CLK] = &gcc_qspi_core_clk.clkr, [GCC_QSPI_CNOC_PERIPH_AHB_CLK] = &gcc_qspi_cnoc_periph_ahb_clk.clkr, + [GCC_LPASS_Q6_AXI_CLK] = &gcc_lpass_q6_axi_clk.clkr, + [GCC_LPASS_SWAY_CLK] = &gcc_lpass_sway_clk.clkr, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { diff --git a/drivers/clk/qcom/lpasscc-sdm845.c b/drivers/clk/qcom/lpasscc-sdm845.c new file mode 100644 index 000..2ef7f2a --- /dev/null +++ b/drivers/clk/qcom/lpasscc-sdm845.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#include + +#include "clk-regmap.h" +#include "clk-branch.h" +#include "common.h" + +static struct clk_branch lpass_audio_wrapper_aon_clk = { + .halt_reg = 0x098, + .halt_check = BRANCH_VOTED, + .clkr = { + .enable_reg = 0x098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "lpass_audio_wrapper_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch lpass_q6ss_ahbm_aon_clk = { + .halt_reg = 0x12000, + .halt_check = BRANCH_VOTED, + .clkr
[PATCH v9 0/2] Add support for LPASS clock controller for SDM845
[v9] * Update GCC documentation binding with the protected-clocks list. * Update the GCC code to add the GCC lpass clocks. * This depends on the acceptance of https://lore.kernel.org/lkml/20181105194011.43770-1-swb...@chromium.org/ [v8] * Add CLK_IS_CRITICAL for GCC lpass clocks for lpass clocks access to go through always. [v7] * Cleanup header file inclusions. * Move the comments along with the flags. * Update the commit with details for CLK_IGNORE_UNUSED. [v6] * Update the logic to register the lpass clocks when the device tree property is not present. * Add the CLK_IGNORE_UNUSED flag for the lpass clocks to not gate the clocks at late_init. [v5] * Address the comments in device tree binding to update the reg-names, update the unit address in lpass clock node example and also add reg property for the gcc clock node. * Update the lpass driver to take care of the reg-names. [v4] * Update the description in GCC Documentation binding for 'qcom,lpass-protected'. * Remove 'qcom,lpass-protected' from LPASS Documentation binding. * Update KConfig to use Low Power Audio Subsystem. * Add module_exit() and also update return value for devm_ioremap_resource failure. [v3] * Add a device tree property to identify lpass protected GCC clocks. * Update the GCC driver code to register the lpass clocks when the flag is defined. * Add comment for clocks using the BRANCH_HALT_SKIP flag. * Use platform APIs instead of of_address_to_resource. * Replace devm_ioremap with devm_ioremap_resource. * Use fixed index for 'lpass_cc' & 'lpass_qdsp6ss' in probe. [v2] * Make gcc_lpass_sway_clk static. * Remove using child nodes and use reg-names to differentiate various domains of LPASS CC. Add support for the lpass clock controller found on SDM845 based devices. This would allow lpass peripheral loader drivers to control the clocks to bring the subsystem out of reset. Taniya Das (2): dt-bindings: clock: Introduce QCOM LPASS clock bindings clk: qcom: Add lpass clock controller driver for SDM845 .../devicetree/bindings/clock/qcom,gcc.txt | 16 ++ .../devicetree/bindings/clock/qcom,lpasscc.txt | 26 +++ drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sdm845.c | 30 drivers/clk/qcom/lpasscc-sdm845.c | 192 + include/dt-bindings/clock/qcom,gcc-sdm845.h| 2 + include/dt-bindings/clock/qcom,lpass-sdm845.h | 16 ++ 8 files changed, 292 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lpasscc.txt create mode 100644 drivers/clk/qcom/lpasscc-sdm845.c create mode 100644 include/dt-bindings/clock/qcom,lpass-sdm845.h -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
[PATCH v9 1/2] dt-bindings: clock: Introduce QCOM LPASS clock bindings
Add device tree bindings for Low Power Audio subsystem clock controller for Qualcomm Technology Inc's SDM845 SoCs. Signed-off-by: Taniya Das --- .../devicetree/bindings/clock/qcom,gcc.txt | 16 + .../devicetree/bindings/clock/qcom,lpasscc.txt | 26 ++ include/dt-bindings/clock/qcom,gcc-sdm845.h| 2 ++ include/dt-bindings/clock/qcom,lpass-sdm845.h | 16 + 4 files changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lpasscc.txt create mode 100644 include/dt-bindings/clock/qcom,lpass-sdm845.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 52d9345..8661c3c 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -35,6 +35,8 @@ be part of GCC and hence the TSENS properties can also be part of the GCC/clock-controller node. For more details on the TSENS properties please refer Documentation/devicetree/bindings/thermal/qcom-tsens.txt +- protected-clocks : Protected clock specifier list as per common clock + binding. Example: clock-controller@90 { @@ -55,3 +57,17 @@ Example of GCC with TSENS properties: #reset-cells = <1>; #thermal-sensor-cells = <1>; }; + +Example of GCC with protected-clocks properties: + clock-controller@10 { + compatible = "qcom,gcc-sdm845"; + reg = <0x10 0x1f>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + protected-clocks = , + , + , + , + ; + }; diff --git a/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt new file mode 100644 index 000..b9e9787 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,lpasscc.txt @@ -0,0 +1,26 @@ +Qualcomm LPASS Clock Controller Binding +--- + +Required properties : +- compatible : shall contain "qcom,sdm845-lpasscc" +- #clock-cells : from common clock binding, shall contain 1. +- reg : shall contain base register address and size, + in the order + Index-0 maps to LPASS_CC register region + Index-1 maps to LPASS_QDSP6SS register region + +Optional properties : +- reg-names: register names of LPASS domain +"cc", "qdsp6ss". + +Example: + +The below node has to be defined in the cases where the LPASS peripheral loader +would bring the subsystem out of reset. + + lpasscc: clock-controller@17014000 { + compatible = "qcom,sdm845-lpasscc"; + reg = <0x17014000 0x1f004>, <0x1730 0x200>; + reg-names = "cc", "qdsp6ss"; + #clock-cells = <1>; + }; diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h index b8eae5a..968fa65 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h @@ -197,6 +197,8 @@ #define GCC_QSPI_CORE_CLK_SRC 187 #define GCC_QSPI_CORE_CLK 188 #define GCC_QSPI_CNOC_PERIPH_AHB_CLK 189 +#define GCC_LPASS_Q6_AXI_CLK 190 +#define GCC_LPASS_SWAY_CLK 191 /* GCC Resets */ #define GCC_MMSS_BCR 0 diff --git a/include/dt-bindings/clock/qcom,lpass-sdm845.h b/include/dt-bindings/clock/qcom,lpass-sdm845.h new file mode 100644 index 000..015968e --- /dev/null +++ b/include/dt-bindings/clock/qcom,lpass-sdm845.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H +#define _DT_BINDINGS_CLK_SDM_LPASS_SDM845_H + +#define LPASS_AUDIO_WRAPPER_AON_CLK0 +#define LPASS_Q6SS_AHBM_AON_CLK1 +#define LPASS_Q6SS_AHBS_AON_CLK2 +#define LPASS_QDSP6SS_XO_CLK 3 +#define LPASS_QDSP6SS_SLEEP_CLK4 +#define LPASS_QDSP6SS_CORE_CLK 5 + +#endif -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.
Re: [PATCH] clk: qcom: gcc: Fix board clock node name
Hello Vinod, On 11/9/2018 3:20 PM, Vinod Koul wrote: Device tree node name are not supposed to have "_" in them so fix the node name use of xo_board to xo-board Fixes: 652f1813c113 ("clk: qcom: gcc: Add global clock controller driver for QCS404") Signed-off-by: Vinod Koul --- Steve: RobH pointed this on DTS patches, would be great if you can pick this as a fix drivers/clk/qcom/gcc-qcs404.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c index e4ca6a45f313..ef1b267cb058 100644 --- a/drivers/clk/qcom/gcc-qcs404.c +++ b/drivers/clk/qcom/gcc-qcs404.c @@ -265,7 +265,7 @@ static struct clk_fixed_factor cxo = { .div = 1, .hw.init = &(struct clk_init_data){ .name = "cxo", - .parent_names = (const char *[]){ "xo_board" }, + .parent_names = (const char *[]){ "xo-board" }, .num_parents = 1, .ops = &clk_fixed_factor_ops, }, This fixed clock needs to be removed, once the RPM<->SMD clocks are added. Why not have this clock part of the device Tree? -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH 2/2] cpufreq: qcom-hw: Add support for QCOM cpufreq HW driver
Hello Stephen, Thanks for your comments. On 11/4/2018 9:50 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-11-02 20:06:00) Hello Stephen, On 10/18/2018 5:02 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-10-11 04:36:01) --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -121,6 +121,17 @@ config ARM_QCOM_CPUFREQ_KRYO If in doubt, say N. +config ARM_QCOM_CPUFREQ_HW + bool "QCOM CPUFreq HW driver" Is there any reason this can't be a module? We do not have any use cases where we need to support it as module. Ok, so it could easily be tristate then? Why not allow it? I have checked other vendors CPUfreq drivers and those too support only "bool". diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c new file mode 100644 index 000..fe1c264 --- /dev/null +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ [...] + +static const u16 cpufreq_qcom_std_offsets[REG_ARRAY_SIZE] = { Is this going to change in the future? Yes, they could change and that was the reason to introduce the offsets. This was discussed earlier too with Sudeep and was to add them. + [REG_ENABLE]= 0x0, This is only used once? Maybe it could be removed. + [REG_LUT_TABLE] = 0x110, And this is only used during probe to figure out the supported frequencies. So we definitely don't need to store around the registers after probe in an array of iomem pointers. The only one that we need after probe is the one below. + [REG_PERF_STATE]= 0x920, +}; + As these address offsets could change, so I am of the opinion to leave them as it is. +static struct cpufreq_qcom *qcom_freq_domain_map[NR_CPUS]; + +static int +qcom_cpufreq_hw_target_index(struct cpufreq_policy *policy, +unsigned int index) +{ + struct cpufreq_qcom *c = policy->driver_data; + + writel_relaxed(index, c->reg_bases[REG_PERF_STATE]); Why can't we avoid the indirection here and store the perf_state pointer in probe? Then we don't have to indirect through a table to perform the register write. As the offsets could change and that was the reason to add this. With fast switching we can avoid incurring any extra instructions, so please make another iomem pointer in the cpufreq_qcom struct just for writing the index or if possible, just pass the iomem pointer that points to the REG_PERF_STATE as the policy->driver_data variable here. Then we have the address in hand without any extra load. If my understanding is correct, we don't need to keep around anything besides this register address anyway so we should be able to just load it and write it immediately. The c->reg_bases[] is just an index to the updated bases addresses. I am not clear as to why it would incur an extra instruction. The below code would already take care of it. + for (i = REG_ENABLE; i < REG_ARRAY_SIZE; i++) + c->reg_bases[i] = base + offsets[i]; + -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v3 3/3] clk: qcom: Add display clock controller driver for SDM845
Hello Stephen, Thanks for your review comments. On 7/9/2018 5:24 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-06-23 07:19:27) diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c new file mode 100644 index 000..af437e0 --- /dev/null +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: GPL-2.0 [...] +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x20d0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, Why is there the no cache flag? Last time I asked I don't think I got any answer, and there isn't a comment here so please at least add a comment to the code so we don't forget. I think you missed my comment from the earlier email. I would add the comment and submit again. > Why is the nocache flag needed? Applies to all clks in this file. > This flag is required for all RCGs whose PLLs are controlled outside the clock controller. The display code would require the recalculated rate always. + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = { + .cmd_rcgr = 0x20ec, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte1_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_byte2_ops, + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_esc0_clk_src[] = { + F(1920, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { + .cmd_rcgr = 0x2108, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc0_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { + .cmd_rcgr = 0x2120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_esc1_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + [...] + +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION? -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v3 3/3] clk: qcom: Add display clock controller driver for SDM845
On 7/9/2018 11:46 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-07-08 20:38:03) Hello Stephen, Thanks for your review comments. On 7/9/2018 5:24 AM, Stephen Boyd wrote: Quoting Taniya Das (2018-06-23 07:19:27) diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c new file mode 100644 index 000..af437e0 --- /dev/null +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: GPL-2.0 [...] +static struct clk_alpha_pll disp_cc_pll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x20d0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_0, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_byte0_clk_src", + .parent_names = disp_cc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, Why is there the no cache flag? Last time I asked I don't think I got any answer, and there isn't a comment here so please at least add a comment to the code so we don't forget. I think you missed my comment from the earlier email. I would add the comment and submit again. Hmm.. ok. > Why is the nocache flag needed? Applies to all clks in this file. > This flag is required for all RCGs whose PLLs are controlled outside the clock controller. The display code would require the recalculated rate always. Right. Why is the PLL controlled outside of the clock controller? The rate should propagate upward to the PLL from here, so who's going outside of that? The DSI0/1 PLL are not part of the display clock controller, but in the display subsystem which are managed by the DRM drivers. When DRM drivers query for the rate clock driver should always return the non cached rates. -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
Re: [PATCH v3 3/3] clk: qcom: Add display clock controller driver for SDM845
On 7/9/2018 1:07 PM, Stephen Boyd wrote: Quoting Taniya Das (2018-07-09 00:07:21) On 7/9/2018 11:46 AM, Stephen Boyd wrote: > Why is the nocache flag needed? Applies to all clks in this file. > This flag is required for all RCGs whose PLLs are controlled outside the clock controller. The display code would require the recalculated rate always. Right. Why is the PLL controlled outside of the clock controller? The rate should propagate upward to the PLL from here, so who's going outside of that? The DSI0/1 PLL are not part of the display clock controller, but in the display subsystem which are managed by the DRM drivers. When DRM drivers query for the rate clock driver should always return the non cached rates. Why? Is the DSI PLL changing rate all the time, randomly, without going through the clk APIs to do so? Hmm, I am afraid I do not have an answer for this, but this was the requirement to always return the non cached rates from the clock driver. -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation. --
[PATCH v2 0/2] clk: qcom: Add support for RCG to register for DFS
[v2] * Move the dfs register function 'qcom_cc_register_rcg_dfs' to clk-rcg2.c instead of common.c * At boot read the DFS enable register and override the clk_ops to be used for dfs or non-dfs RCGs. * Remove flag 'dfs_enabled'. * Remove functions 'clk_rcg2_dfs_determine_rate_lazy' * Remove 'struct dfs_table *dfs_entry' * Remove '_freq_tbl_determine_dfs_rate' * Combine the function 'clk_index_pre_div_and_mode' and 'calculate_m_and_n' to a single function and named it 'clk_rcg2_calculate_m_and_n'. * Remove taking M/N/PERF offsets as function arguments. * Add clocks in gcc-sdm845.c the DFS clock array to register. [v1] * Update SPDX for files. * Add new clk_ops for DFS mode which would be used if dfs is enabled, else fall back to the clk_rcg2_shared_ops. * Use kcalloc in place kzalloc. * Fixed the return type for 'clk_parent_index_pre_div_and_mode' which is now renamed to 'clk_index_pre_div_and_mode'. * Removed return of -EPERM from 'clk_rcg2_set_rate' and new dfs clk_ops is introduced. * Pass frequency table entry structure to function calculate_m_and_n. * Remove desc from qcom_cc_register_rcg_dfs and instead pass array of clk_rcg2. * Add a dfs_enable flag to identify if dfs mode is enabled. In the cases where a RCG requires a Dynamic Frequency switch support requires to register which would at runtime read the clock perf level registers to identify the frequencies supported and update the frequency table accordingly. Taniya Das (2): clk: qcom: Add support for RCG to register for DFS clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845 drivers/clk/qcom/clk-rcg.h| 5 + drivers/clk/qcom/clk-rcg2.c | 214 ++ drivers/clk/qcom/common.c | 14 +-- drivers/clk/qcom/common.h | 16 +--- drivers/clk/qcom/gcc-sdm845.c | 27 +- 5 files changed, 250 insertions(+), 26 deletions(-) -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.