Skip to contentSkip to conversation

clk: qcom: CPU clock driver for msm8996

PATCH Superseded Ilia Lin 4 participants 39 messages Feb 14, 2018 – Apr 6, 2018

Subsystems (8)

v3 of 12 Superseded Latest is v12 →

lore
Share & tools
lore

Ilia Lin

author
#0 lore raw

v3 cover clk: qcom: CPU clock driver for msm8996

[v3]
* Rebased on top of the latest PLL driver changes
* Addressed comment from Rob Herring for bindings

This series adds support for the CPU clocks on msm8996 devices.

The driver uses the existing PLL drivers and is required to control the CPU frequency scaling on the MSM8996.

A previous post of RFC can be found here
https://patchwork.kernel.org/patch/10144485/

Ilia Lin (6):
soc: qcom: Separate kryo l2 accessors from PMU driver
clk: qcom: Add DT bindings for CPU clock driver for msm8996
clk: qcom: clk-cpu-8996: Prepare PLLs on probe
clk: qcom: Add ACD path to CPU clock driver for msm8996
DT: QCOM: Add cpufreq-dt to msm8996
DT: QCOM: Add thermal mitigation to msm8996

Rajendra Nayak (4):
clk: qcom: Make clk_alpha_pll_configure available to modules
clk: qcom: Add CPU clock driver for msm8996
clk: qcom: cpu-8996: Add support to switch to alternate PLL
clk: qcom: cpu-8996: Add support to switch below 600Mhz

 .../devicetree/bindings/clock/qcom,kryocc.txt      |  17 +
 arch/arm64/Kconfig.platforms                       |   7 +
 arch/arm64/boot/dts/qcom/apq8096-db820c.dts        |   4 +-
 arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi       |   2 +-
 arch/arm64/boot/dts/qcom/msm8996.dtsi              | 286 ++++++++++-
 drivers/clk/qcom/Kconfig                           |   8 +
 drivers/clk/qcom/Makefile                          |   1 +
 drivers/clk/qcom/clk-alpha-pll.c                   |   1 +
 drivers/clk/qcom/clk-cpu-8996.c                    | 554 +++++++++++++++++++++
 drivers/cpufreq/cpufreq-dt-platdev.c               |   3 +
 drivers/perf/qcom_l2_pmu.c                         |  50 +-
 drivers/soc/qcom/Makefile                          |   1 +
 drivers/soc/qcom/kryo-l2-accessors.c               |  64 +++
 include/soc/qcom/kryo-l2-accessors.h               |  22 +
 14 files changed, 956 insertions(+), 64 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/qcom,kryocc.txt
 create mode 100644 drivers/clk/qcom/clk-cpu-8996.c
 create mode 100644 drivers/soc/qcom/kryo-l2-accessors.c
 create mode 100644 include/soc/qcom/kryo-l2-accessors.h
Signature · 1 line
1.9.1
author
#1 lore raw

PATCH v3 1/10 soc: qcom: Separate kryo l2 accessors from PMU driver

The driver provides kernel level API for other drivers to access the MSM8996 L2 cache registers. Separating the L2 access code from the PMU driver and making it public to allow other drivers use it. The accesses must be separated with a single spinlock, maintained in this driver.

---
 arch/arm64/Kconfig.platforms         |  7 ++++
 drivers/perf/qcom_l2_pmu.c           | 50 ++--------------------------
 drivers/soc/qcom/Makefile            |  1 +
 drivers/soc/qcom/kryo-l2-accessors.c | 64 ++++++++++++++++++++++++++++++++++++
 include/soc/qcom/kryo-l2-accessors.h | 22 +++++++++++++
 5 files changed, 96 insertions(+), 48 deletions(-)
 create mode 100644 drivers/soc/qcom/kryo-l2-accessors.c
 create mode 100644 include/soc/qcom/kryo-l2-accessors.h
arch/arm64/Kconfig.platforms +7 -0
index fbedbd8..78a103b 100644
@@ -145,6 +145,13 @@ config ARCH_REALTEK
 	  This enables support for the ARMv8 based Realtek chipsets,
 	  like the RTD1295.
 
+config ARCH_MSM8996
+    bool "Enable Support for Qualcomm Technologies, Inc. MSM8996"
+	depends on ARCH_QCOM
+	help
+	This enables support for the MSM8996 chipset. If you do not
+	wish to build a kernel that runs on this chipset, say 'N' here.
+
 config ARCH_ROCKCHIP
 	bool "Rockchip Platforms"
 	select ARCH_HAS_RESET_CONTROLLER
drivers/perf/qcom_l2_pmu.c +2 -48

71 lines not on this page · raw message

drivers/soc/qcom/Makefile +1 -0
index dcebf28..4e91e2a 100644
@@ -12,3 +12,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
 obj-$(CONFIG_QCOM_SMP2P)	+= smp2p.o
 obj-$(CONFIG_QCOM_SMSM)	+= smsm.o
 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
+obj-$(CONFIG_ARCH_MSM8996) +=	kryo-l2-accessors.o
drivers/soc/qcom/kryo-l2-accessors.c new file +64 -0

64 lines not on this page · raw message

include/soc/qcom/kryo-l2-accessors.h new file +22 -0
new file mode 100644
index 0000000..e9a5eab
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H
+#define __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H
+
+#ifdef CONFIG_ARCH_QCOM
+void set_l2_indirect_reg(u64 reg_addr, u64 val);
+u64 get_l2_indirect_reg(u64 reg_addr);
+#endif
+
+#endif
Signature · 1 line
1.9.1
maintainer
#2 lore raw

PATCH v3 1/10 soc: qcom: Separate kryo l2 accessors from PMU driver

Quoting Ilia Lin (2018-02-14 05:59:43)

arch/arm64/Kconfig.platforms config ARCH_REALTEK · line 150

Quoted 11 lines
arch/arm64/Kconfig.platforms +3 -0
index fbedbd8..78a103b 100644
@@ -145,6 +145,13 @@ config ARCH_REALTEK
          This enables support for the ARMv8 based Realtek chipsets,
          like the RTD1295.
 
+config ARCH_MSM8996
+    bool "Enable Support for Qualcomm Technologies, Inc. MSM8996"
+       depends on ARCH_QCOM

Is this really the proposed approach? Doesn't the PMU code use these accessors? I would think the accessors are compiled if ARCH_QCOM=y so that the PMU stuff keeps working. Drop this Kconfig addition?

Quoted 12 lines
arch/arm64/Kconfig.platforms +4 -0
+       help
+       This enables support for the MSM8996 chipset. If you do not
+       wish to build a kernel that runs on this chipset, say 'N' here.
+
 config ARCH_ROCKCHIP
        bool "Rockchip Platforms"
        select ARCH_HAS_RESET_CONTROLLER
drivers/perf/qcom_l2_pmu.c +0 -0
index 4fdc848..8cece9e 100644

drivers/perf/qcom_l2_pmu.c line 1

Quoted 2 lines
drivers/perf/qcom_l2_pmu.c +1 -1
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.

Sorry, this makes little sense. First off, code is only being deleted and more than half the file isn't being modified so why update copyright dates?

Quoted 20 lines
drivers/perf/qcom_l2_pmu.c +0 -0
  *
  * 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
drivers/soc/qcom/Makefile +1 -0
index dcebf28..4e91e2a 100644
@@ -12,3 +12,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
 obj-$(CONFIG_QCOM_SMP2P)       += smp2p.o
 obj-$(CONFIG_QCOM_SMSM)        += smsm.o
 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
+obj-$(CONFIG_ARCH_MSM8996) +=  kryo-l2-accessors.o
drivers/soc/qcom/kryo-l2-accessors.c new file +2 -0
new file mode 100644
index 0000000..6743848
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.

drivers/soc/qcom/kryo-l2-accessors.c line 12

Quoted 10 lines
drivers/soc/qcom/kryo-l2-accessors.c new file +10 -0
+ *
+ * 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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 tags?

Quoted 11 lines
include/soc/qcom/kryo-l2-accessors.h new file +5 -0
new file mode 100644
index 0000000..e9a5eab
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 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

include/soc/qcom/kryo-l2-accessors.h line 15

Quoted 10 lines
include/soc/qcom/kryo-l2-accessors.h new file +10 -0
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H
+#define __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H

Maybe change this tO __SOC_ARCH_QCOM_KRYO_L2_ACCESSORS_H

include/soc/qcom/kryo-l2-accessors.h line 20

Quoted 5 lines
include/soc/qcom/kryo-l2-accessors.h new file +5 -0
+
+#ifdef CONFIG_ARCH_QCOM
+void set_l2_indirect_reg(u64 reg_addr, u64 val);
+u64 get_l2_indirect_reg(u64 reg_addr);
+#endif

This ifdef isn't doing much. Drop it? Or provide the inline nop alternatives.

#3 lore raw

PATCH v3 1/10 soc: qcom: Separate kryo l2 accessors from PMU driver

Quoted 24 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Monday, March 19, 2018 19:45
To: Ilia Lin <[email protected]>; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; linux-clk at vger.kernel.org;
sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; ilialin at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: Re: [PATCH v3 01/10] soc: qcom: Separate kryo l2 accessors from PMU driver

Quoting Ilia Lin (2018-02-14 05:59:43)

Quoted 8 lines
(quoted diff) +0 -0

b/arch/arm64/Kconfig.platforms index fbedbd8..78a103b 100644

arch/arm64/Kconfig.platforms +0 -0
@@ -145,6 +145,13 @@ config ARCH_REALTEK
          This enables support for the ARMv8 based Realtek chipsets,
          like the RTD1295.
 
Quoted 7 lines

arch/arm64/Kconfig.platforms config ARCH_REALTEK · line 150

Quoted 3 lines
arch/arm64/Kconfig.platforms +3 -0
+config ARCH_MSM8996
+    bool "Enable Support for Qualcomm Technologies, Inc. MSM8996"
+       depends on ARCH_QCOM

Is this really the proposed approach? Doesn't the PMU code use these accessors? I would think the accessors are compiled if ARCH_QCOM=y so that the PMU stuff keeps working. Drop this Kconfig addition?

I'll check whether the kryo-accessors code is SOC specific or not.

Quoted 10 lines
Quoted 10 lines
arch/arm64/Kconfig.platforms +4 -0
+       help
+       This enables support for the MSM8996 chipset. If you do not
+       wish to build a kernel that runs on this chipset, say 'N' here.
+
 config ARCH_ROCKCHIP
        bool "Rockchip Platforms"
        select ARCH_HAS_RESET_CONTROLLER diff --git

a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c index 4fdc848..8cece9e 100644

Quoted 8 lines

drivers/perf/qcom_l2_pmu.c line 1

Quoted 5 lines
drivers/perf/qcom_l2_pmu.c +1 -1
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.

Sorry, this makes little sense. First off, code is only being deleted and more than half the file isn't being modified so why update copyright dates?

Agree. Will roll back.

Quoted 28 lines

drivers/soc/qcom/Makefile obj-$(CONFIG_QCOM_SMEM_STATE) +=

Quoted 9 lines
drivers/perf/qcom_l2_pmu.c +0 -0
  *
  * 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
drivers/soc/qcom/Makefile +0 -0
index dcebf28..4e91e2a 100644
@@ -12,3 +12,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) +=

smem_state.o

Quoted 18 lines
drivers/soc/qcom/Makefile +1 -0
 obj-$(CONFIG_QCOM_SMP2P)       += smp2p.o
 obj-$(CONFIG_QCOM_SMSM)        += smsm.o
 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
+obj-$(CONFIG_ARCH_MSM8996) +=  kryo-l2-accessors.o
drivers/soc/qcom/kryo-l2-accessors.c new file +7 -0
new file mode 100644
index 0000000..6743848
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014-2015, 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
+ * only version 2 as published by the Free Software Foundation.
Quoted 8 lines

drivers/soc/qcom/kryo-l2-accessors.c line 12

Quoted 6 lines
drivers/soc/qcom/kryo-l2-accessors.c new file +6 -0
+ *
+ * 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 tags?

Will do.

Quoted 18 lines
Quoted 18 lines
include/soc/qcom/kryo-l2-accessors.h new file +10 -0
new file mode 100644
index 0000000..e9a5eab
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Quoted 8 lines

include/soc/qcom/kryo-l2-accessors.h line 15

Quoted 6 lines
include/soc/qcom/kryo-l2-accessors.h new file +6 -0
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H
+#define __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H

Maybe change this tO __SOC_ARCH_QCOM_KRYO_L2_ACCESSORS_H

No problem. Will change.

Quoted 7 lines

include/soc/qcom/kryo-l2-accessors.h

Quoted 5 lines
include/soc/qcom/kryo-l2-accessors.h new file +4 -0
+
+#ifdef CONFIG_ARCH_QCOM
+void set_l2_indirect_reg(u64 reg_addr, u64 val);
+u64 get_l2_indirect_reg(u64 reg_addr); #endif

This ifdef isn't doing much. Drop it? Or provide the inline nop alternatives.

Right. I'll drop it.

author
#4 lore raw

PATCH v3 2/10 clk: qcom: Make clk_alpha_pll_configure available to modules

In reply to Ilia Lin

From: Rajendra Nayak <[email protected]>

Allow clk_alpha_pll_configure to be called from loadable kernel modules.

---
 drivers/clk/qcom/clk-alpha-pll.c | 1 +
 1 file changed, 1 insertion(+)
drivers/clk/qcom/clk-alpha-pll.c +1 -0
index 6d04cd9..5c962af 100644
@@ -208,6 +208,7 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
 	if (pll->flags & SUPPORTS_FSM_MODE)
 		qcom_pll_set_fsm_mode(regmap, PLL_MODE(pll), 6, 0);
 }
+EXPORT_SYMBOL_GPL(clk_alpha_pll_configure);
 
 static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)
 {
Signature · 1 line
1.9.1
author
#6 lore raw

PATCH v3 3/10 clk: qcom: Add CPU clock driver for msm8996

In reply to Ilia Lin

From: Rajendra Nayak <[email protected]>

Each of the CPU clusters (Power and Perf) on msm8996 are clocked via 2 PLLs, a primary and alternate. There are also 2 Mux'es, a primary and secondary all connected together as shown below

                             +-------+
              XO             |       |
          +------------------>0      |
                             |       |
                   PLL/2     | SMUX  +----+
                     +------->1      |    |
                     |       |       |    |
                     |       +-------+    |    +-------+
                     |                    +---->0      |
                     |                         |       |
+---------------+    |             +----------->1      | CPU clk
|Primary PLL    +----+ PLL_EARLY   |           |       +------>
|               +------+-----------+    +------>2 PMUX |
+---------------+      |                |      |       |
                       |   +------+     |   +-->3      |
                       +--^+  ACD +-----+   |  +-------+
+---------------+          +------+         |
|Alt PLL        |                           |
|               +---------------------------+
+---------------+         PLL_EARLY

The primary PLL is what drives the CPU clk, except for times when we are reprogramming the PLL itself (for rate changes) when we temporarily switch to an alternate PLL. A subsequent patch adds support to switch between primary and alternate PLL during rate changes.

The primary PLL operates on a single VCO range, between 600Mhz and 3Ghz. However the CPUs do support OPPs with frequencies between 300Mhz and 600Mhz. In order to support running the CPUs at those frequencies we end up having to lock the PLL at twice the rate and drive the CPU clk via the PLL/2 output and SMUX.

So for frequencies above 600Mhz we follow the following path
Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
and for frequencies between 300Mhz and 600Mhz we follow
Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk
Support for this is added in a subsequent patch as well.

ACD stands for Adaptive Clock Distribution and is used to detect voltage droops. We do not add support for ACD as yet. This can be added at a later point as needed.

---
 drivers/clk/qcom/Kconfig        |   8 +
 drivers/clk/qcom/Makefile       |   1 +
 drivers/clk/qcom/clk-cpu-8996.c | 409 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 418 insertions(+)
 create mode 100644 drivers/clk/qcom/clk-cpu-8996.c
drivers/clk/qcom/Kconfig +8 -0
index fbf4532..3274877 100644
@@ -226,3 +226,11 @@ config SPMI_PMIC_CLKDIV
 	  Technologies, Inc. SPMI PMIC. It configures the frequency of
 	  clkdiv outputs of the PMIC. These clocks are typically wired
 	  through alternate functions on GPIO pins.
+
+config MSM_APCC_8996
+	tristate "MSM8996 CPU Clock Controller"
+	depends on COMMON_CLK_QCOM
+	help
+	  Support for the CPU clock controller on msm8996 devices.
+	  Say Y if you want to support CPU clock scaling using CPUfreq
+	  drivers for dyanmic power management.
drivers/clk/qcom/Makefile +1 -0
index 230332c..57b38ba 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
 obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+obj-$(CONFIG_MSM_APCC_8996) += clk-cpu-8996.o
 obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
 obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
 obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
drivers/clk/qcom/clk-cpu-8996.c new file +409 -0

409 lines not on this page · raw message

Signature · 1 line
1.9.1
maintainer
#7 lore raw

PATCH v3 3/10 clk: qcom: Add CPU clock driver for msm8996

Quoting Ilia Lin (2018-02-14 05:59:45)

Quoted 19 lines

From: Rajendra Nayak <[email protected]>

Each of the CPU clusters (Power and Perf) on msm8996 are clocked via 2 PLLs, a primary and alternate. There are also 2 Mux'es, a primary and secondary all connected together as shown below

                             +-------+
              XO             |       |
          +------------------>0      |
                             |       |
                   PLL/2     | SMUX  +----+
                     +------->1      |    |
                     |       |       |    |
                     |       +-------+    |    +-------+
                     |                    +---->0      |
                     |                         |       |
+---------------+    |             +----------->1      | CPU clk
|Primary PLL    +----+ PLL_EARLY   |           |       +------>
Quoted 8 lines
|               +------+-----------+    +------>2 PMUX |
+---------------+      |                |      |       |
                       |   +------+     |   +-->3      |
                       +--^+  ACD +-----+   |  +-------+
+---------------+          +------+         |
|Alt PLL        |                           |
|               +---------------------------+
+---------------+         PLL_EARLY

Thanks for the diagram. Please also put it at the top of the driver file.

Quoted 13 lines

The primary PLL is what drives the CPU clk, except for times when we are reprogramming the PLL itself (for rate changes) when we temporarily switch to an alternate PLL. A subsequent patch adds support to switch between primary and alternate PLL during rate changes.

The primary PLL operates on a single VCO range, between 600Mhz and 3Ghz. However the CPUs do support OPPs with frequencies between 300Mhz and 600Mhz. In order to support running the CPUs at those frequencies we end up having to lock the PLL at twice the rate and drive the CPU clk via the PLL/2 output and SMUX.

Quoted 3 lines

So for frequencies above 600Mhz we follow the following path
Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
and for frequencies between 300Mhz and 600Mhz we follow

Capitalize 'h' in units please.

Quoted 22 lines

Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk
Support for this is added in a subsequent patch as well.

ACD stands for Adaptive Clock Distribution and is used to detect voltage droops. We do not add support for ACD as yet. This can be added at a later point as needed.

---
 drivers/clk/qcom/Kconfig        |   8 +
 drivers/clk/qcom/Makefile       |   1 +
 drivers/clk/qcom/clk-cpu-8996.c | 409 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 418 insertions(+)
 create mode 100644 drivers/clk/qcom/clk-cpu-8996.c
drivers/clk/qcom/Kconfig +0 -0
index fbf4532..3274877 100644
@@ -226,3 +226,11 @@ config SPMI_PMIC_CLKDIV
          Technologies, Inc. SPMI PMIC. It configures the frequency of

drivers/clk/qcom/Kconfig config SPMI_PMIC_CLKDIV · line 236

Quoted 10 lines
drivers/clk/qcom/Kconfig +8 -0
          clkdiv outputs of the PMIC. These clocks are typically wired
          through alternate functions on GPIO pins.
+
+config MSM_APCC_8996
+       tristate "MSM8996 CPU Clock Controller"
+       depends on COMMON_CLK_QCOM
+       help
+         Support for the CPU clock controller on msm8996 devices.
+         Say Y if you want to support CPU clock scaling using CPUfreq
+         drivers for dyanmic power management.

Sort?

drivers/clk/qcom/Makefile obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o · line 36

Quoted 9 lines
drivers/clk/qcom/Makefile +1 -0
index 230332c..57b38ba 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
 obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+obj-$(CONFIG_MSM_APCC_8996) += clk-cpu-8996.o

This doesn't look sorted.

Quoted 11 lines
drivers/clk/qcom/Makefile +0 -0
 obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
 obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
 obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
drivers/clk/qcom/clk-cpu-8996.c new file +2 -0
new file mode 100644
index 0000000..42489f1
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.

drivers/clk/qcom/clk-cpu-8996.c line 12

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+ *
+ * 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */

Can we get the SPDX tags here please?

drivers/clk/qcom/clk-cpu-8996.c line 14

Quoted 2 lines
drivers/clk/qcom/clk-cpu-8996.c new file +2 -0
+
+#include <linux/clk.h>

clk-provider.h?

drivers/clk/qcom/clk-cpu-8996.c line 19

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c new file +5 -0
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "clk-alpha-pll.h"

#include "clk-regmap.h"

drivers/clk/qcom/clk-cpu-8996.c line 25

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+
+#define VCO(a, b, c) { \
+       .val = a,\
+       .min_freq = b,\
+       .max_freq = c,\
+}

Can this define go into whatever PLL header file defines the struct?

drivers/clk/qcom/clk-cpu-8996.c line 37

Quoted 12 lines
drivers/clk/qcom/clk-cpu-8996.c new file +12 -0
+
+#define DIV_2_INDEX            0
+#define PLL_INDEX              1
+#define ACD_INDEX              2
+#define ALT_INDEX              3
+
+static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
+       [PLL_OFF_L_VAL] = 0x04,
+       [PLL_OFF_ALPHA_VAL] = 0x08,
+       [PLL_OFF_USER_CTL] = 0x10,
+       [PLL_OFF_CONFIG_CTL] = 0x18,
+       [PLL_OFF_CONFIG_CTL_U] = 0x1C,

Please use lowercase hex throughout. Consistency is key!

Quoted 94 lines
drivers/clk/qcom/clk-cpu-8996.c new file +94 -0
+       [PLL_OFF_TEST_CTL] = 0x20,
+       [PLL_OFF_TEST_CTL_U] = 0x24,
+       [PLL_OFF_STATUS] = 0x28,
+};
+
+static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
+       [PLL_OFF_L_VAL] = 0x04,
+       [PLL_OFF_ALPHA_VAL] = 0x08,
+       [PLL_OFF_ALPHA_VAL_U] = 0x0c,
+       [PLL_OFF_USER_CTL] = 0x10,
+       [PLL_OFF_USER_CTL_U] = 0x14,
+       [PLL_OFF_CONFIG_CTL] = 0x18,
+       [PLL_OFF_TEST_CTL] = 0x20,
+       [PLL_OFF_TEST_CTL_U] = 0x24,
+       [PLL_OFF_STATUS] = 0x28,
+};
+
+/* PLLs */
+
+static const struct alpha_pll_config hfpll_config = {
+       .l = 60,
+       .config_ctl_val = 0x200d4828,
+       .config_ctl_hi_val = 0x006,
+       .pre_div_mask = BIT(12),
+       .post_div_mask = 0x3 << 8,
+       .main_output_mask = BIT(0),
+       .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_pll = {
+       .offset = 0x80000,
+       .regs = prim_pll_regs,
+       .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "perfcl_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_huayra_ops,
+       },
+};
+
+static struct clk_alpha_pll pwrcl_pll = {
+       .offset = 0x0,
+       .regs = prim_pll_regs,
+       .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pwrcl_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_huayra_ops,
+       },
+};
+
+static const struct pll_vco alt_pll_vco_modes[] = {
+       VCO(3,  250000000,  500000000),
+       VCO(2,  500000000,  750000000),
+       VCO(1,  750000000, 1000000000),
+       VCO(0, 1000000000, 2150400000),
+};
+
+static const struct alpha_pll_config altpll_config = {
+       .l = 16,
+       .vco_val = 0x3 << 20,
+       .vco_mask = 0x3 << 20,
+       .config_ctl_val = 0x4001051b,
+       .post_div_mask = 0x3 << 8,
+       .post_div_val = 0x1,
+       .main_output_mask = BIT(0),
+       .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_alt_pll = {
+       .offset = 0x80100,
+       .regs = alt_pll_regs,
+       .vco_table = alt_pll_vco_modes,
+       .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+       .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "perfcl_alt_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_hwfsm_ops,
+       },
+};
+
+static struct clk_alpha_pll pwrcl_alt_pll = {
+       .offset = 0x100,
+       .regs = alt_pll_regs,
+       .vco_table = alt_pll_vco_modes,
+       .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+       .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "pwrcl_alt_pll",
+               .parent_names = (const char *[]){ "xo" },

drivers/clk/qcom/clk-cpu-8996.c line 141

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_hwfsm_ops,
+       },
+};
+
+/* Mux'es */
+
+struct clk_cpu_8996_mux {
+       u32     reg;
+       u32     shift;

u8 shift?

drivers/clk/qcom/clk-cpu-8996.c line 142

Quoted 1 line
drivers/clk/qcom/clk-cpu-8996.c new file +1 -0
+       u32     width;

u8 width?

Quoted 13 lines
drivers/clk/qcom/clk-cpu-8996.c new file +13 -0
+       struct clk_hw   *pll;
+       struct clk_regmap clkr;
+};
+
+static inline
+struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)
+{
+       return container_of(to_clk_regmap(hw), struct clk_cpu_8996_mux, clkr);
+}
+
+static u8 clk_cpu_8996_mux_get_parent(struct clk_hw *hw)
+{
+       unsigned int val;

drivers/clk/qcom/clk-cpu-8996.c line 165

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+       struct clk_regmap *clkr = to_clk_regmap(hw);
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       unsigned int mask = GENMASK(cpuclk->width - 1, 0);
+
+       regmap_read(clkr->regmap, cpuclk->reg, &val);
+
+       val >>= cpuclk->shift;
+       val &= mask;
+
+       return val;

return val & mask;

drivers/clk/qcom/clk-cpu-8996.c line 170

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c new file +5 -0
+}
+
+static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+       unsigned int val;

u32 val?

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c new file +9 -0
+       struct clk_regmap *clkr = to_clk_regmap(hw);
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       unsigned int mask = GENMASK(cpuclk->width + cpuclk->shift - 1,
+                                   cpuclk->shift);
+
+       val = index;
+       val <<= cpuclk->shift;
+
+       return regmap_update_bits(clkr->regmap, cpuclk->reg, mask, val);

drivers/clk/qcom/clk-cpu-8996.c line 189

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+}
+
+static int
+clk_cpu_8996_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       struct clk_hw *parent = cpuclk->pll;
+
+       if (!cpuclk->pll)
+               return -EINVAL;

Does this happen?

drivers/clk/qcom/clk-cpu-8996.c line 192

Quoted 3 lines
drivers/clk/qcom/clk-cpu-8996.c new file +3 -0
+
+       req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
+       req->best_parent_hw = parent;

Is the parent index always the same? Perhaps just call clk_hw_get_parent_by_index() then instead of adding a pointer to the clk_cpu_8996_mux.

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c new file +9 -0
+
+       return 0;
+}
+
+const struct clk_ops clk_cpu_8996_mux_ops = {
+       .set_parent = clk_cpu_8996_mux_set_parent,
+       .get_parent = clk_cpu_8996_mux_get_parent,
+       .determine_rate = clk_cpu_8996_mux_determine_rate,
+};

[...]

Quoted 26 lines
drivers/clk/qcom/clk-cpu-8996.c new file +26 -0
+
+static struct clk_cpu_8996_mux pwrcl_pmux = {
+       .reg = 0x40,
+       .shift = 0,
+       .width = 2,
+       .pll = &pwrcl_pll.clkr.hw,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "pwrcl_pmux",
+               .parent_names = (const char *[]){
+                       "pwrcl_smux",
+                       "pwrcl_pll",
+                       "pwrcl_pll_acd",
+                       "pwrcl_alt_pll",
+               },
+               .num_parents = 4,
+               .ops = &clk_cpu_8996_mux_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+       },
+};
+
+static struct clk_cpu_8996_mux perfcl_pmux = {
+       .reg = 0x80040,
+       .shift = 0,
+       .width = 2,
+       .pll = &perfcl_pll.clkr.hw,
+       .clkr.hw.init = &(struct clk_init_data) {

drivers/clk/qcom/clk-cpu-8996.c line 269

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+               .name = "perfcl_pmux",
+               .parent_names = (const char *[]){
+                       "perfcl_smux",
+                       "perfcl_pll",
+                       "perfcl_pll_acd",
+                       "perfcl_alt_pll",
+               },
+               .num_parents = 4,
+               .ops = &clk_cpu_8996_mux_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,

Not sure CLK_IS_CRITICAL is the right mode. Perhaps CLK_IGNORE_UNUSED for now? We don't want to force XO to stay on forever here.

drivers/clk/qcom/clk-cpu-8996.c line 282

Quoted 13 lines
drivers/clk/qcom/clk-cpu-8996.c new file +13 -0
+       },
+};
+
+static const struct regmap_config cpu_msm8996_regmap_config = {
+       .reg_bits               = 32,
+       .reg_stride             = 4,
+       .val_bits               = 32,
+       .max_register           = 0x80210,
+       .fast_io                = true,
+       .val_format_endian      = REGMAP_ENDIAN_LITTLE,
+};
+
+static const struct of_device_id match_table[] = {

Move this next to driver structure and give it a more specific name.

Quoted 1 line

+ { .compatible = "qcom-msm8996-apcc" },

Bad compatible? Should be qcom,msm8996-apcc?

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c new file +4 -0
+       {}
+};
+
+struct clk_regmap *clks[] = {

drivers/clk/qcom/clk-cpu-8996.c line 297

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+       /* PLLs */
+       &perfcl_pll.clkr,
+       &pwrcl_pll.clkr,
+       &perfcl_alt_pll.clkr,
+       &pwrcl_alt_pll.clkr,
+       /* MUXs */
+       &perfcl_smux.clkr,
+       &pwrcl_smux.clkr,
+       &perfcl_pmux.clkr,
+       &pwrcl_pmux.clkr,

Please drop useless comments inside this array.

drivers/clk/qcom/clk-cpu-8996.c line 303

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+};
+
+struct clk_hw_clks {
+       unsigned int num;
+       struct clk_hw *hws[];
+};

Please just NULL terminate the list of clk_hw pointers, or keep the size around instead.

Quoted 8 lines
drivers/clk/qcom/clk-cpu-8996.c new file +8 -0
+
+static int
+qcom_cpu_clk_msm8996_register_clks(struct device *dev, struct clk_hw_clks *hws,
+                                  struct regmap *regmap)
+{
+       int i, ret;
+
+       hws->hws[0] = clk_hw_register_fixed_factor(dev, "perfcl_pll_main",

drivers/clk/qcom/clk-cpu-8996.c line 321

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+                                                  "perfcl_pll",
+                                                  CLK_SET_RATE_PARENT, 1, 2);
+       perfcl_smux.pll = hws->hws[0];
+
+       hws->hws[1] = clk_hw_register_fixed_factor(dev, "pwrcl_pll_main",
+                                                  "pwrcl_pll",
+                                                  CLK_SET_RATE_PARENT, 1, 2);
+       pwrcl_smux.pll = hws->hws[1];
+
+       hws->num = 2;

Maybe just open code the fixed factor clk registration? Then the devm_clk_hw_register() function can be used on those static structs to make removal simpler.

Quoted 11 lines
drivers/clk/qcom/clk-cpu-8996.c new file +11 -0
+
+       for (i = 0; i < ARRAY_SIZE(clks); i++) {
+               ret = devm_clk_register_regmap(dev, clks[i]);
+               if (ret)
+                       return ret;
+       }
+
+       clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
+       clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
+       clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
+       clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);

drivers/clk/qcom/clk-cpu-8996.c line 342

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+
+       return ret;
+}
+
+static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
+{
+       int ret;
+       void __iomem *base;
+       struct resource *res;
+       struct regmap *regmap_cpu;

Just call it regmap please.

Quoted 39 lines
drivers/clk/qcom/clk-cpu-8996.c new file +39 -0
+       struct clk_hw_clks *hws;
+       struct clk_hw_onecell_data *data;
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+
+       data = devm_kzalloc(dev, sizeof(*data) + 2 * sizeof(struct clk_hw *),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       hws = devm_kzalloc(dev, sizeof(*hws) + 2 * sizeof(struct clk_hw *),
+                          GFP_KERNEL);
+       if (!hws)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       regmap_cpu = devm_regmap_init_mmio(dev, base,
+                                          &cpu_msm8996_regmap_config);
+       if (IS_ERR(regmap_cpu))
+               return PTR_ERR(regmap_cpu);
+
+       ret = qcom_cpu_clk_msm8996_register_clks(dev, hws, regmap_cpu);
+       if (ret)
+               return ret;
+
+       data->hws[0] = &pwrcl_pmux.clkr.hw;
+       data->hws[1] = &perfcl_pmux.clkr.hw;
+
+       data->num = 2;
+
+       platform_set_drvdata(pdev, hws);
+
+       return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data);
+}
+

drivers/clk/qcom/clk-cpu-8996.c line 391

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+static int qcom_cpu_clk_msm8996_driver_remove(struct platform_device *pdev)
+{
+       int i;
+       struct device *dev = &pdev->dev;
+       struct clk_hw_clks *hws = platform_get_drvdata(pdev);
+
+       for (i = 0; i < hws->num; i++)
+               clk_hw_unregister_fixed_rate(hws->hws[i]);
+
+       of_clk_del_provider(dev->of_node);

Use devm_of_clk_add_hw_provider() instead.

Quoted 7 lines
drivers/clk/qcom/clk-cpu-8996.c new file +7 -0
+
+       return 0;
+}
+
+static struct platform_driver qcom_cpu_clk_msm8996_driver = {
+       .probe = qcom_cpu_clk_msm8996_driver_probe,
+       .remove = qcom_cpu_clk_msm8996_driver_remove,

drivers/clk/qcom/clk-cpu-8996.c line 408

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+       .driver = {
+               .name = "qcom-msm8996-apcc",
+               .of_match_table = match_table,
+       },
+};
+
+module_platform_driver(qcom_cpu_clk_msm8996_driver);
+
+MODULE_ALIAS("platform:msm8996-apcc");
+MODULE_DESCRIPTION("QCOM MSM8996 CPU clock Driver");

Not sure why Driver is capitalized and clock is not.

#8 lore raw

PATCH v3 3/10 clk: qcom: Add CPU clock driver for msm8996

Quoted 43 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Monday, March 19, 2018 19:37
To: Ilia Lin <[email protected]>; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; linux-clk at vger.kernel.org;
sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; ilialin at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: Re: [PATCH v3 03/10] clk: qcom: Add CPU clock driver for msm8996

Quoting Ilia Lin (2018-02-14 05:59:45)

Quoted 19 lines

From: Rajendra Nayak <[email protected]>

Each of the CPU clusters (Power and Perf) on msm8996 are clocked via 2 PLLs, a primary and alternate. There are also
2 Mux'es, a primary and secondary all connected together as shown below

                             +-------+
              XO             |       |
          +------------------>0      |
                             |       |
                   PLL/2     | SMUX  +----+
                     +------->1      |    |
                     |       |       |    |
                     |       +-------+    |    +-------+
                     |                    +---->0      |
                     |                         |       |
+---------------+    |             +----------->1      | CPU clk
|Primary PLL    +----+ PLL_EARLY   |           |       +------>
Quoted 8 lines
|               +------+-----------+    +------>2 PMUX |
+---------------+      |                |      |       |
                       |   +------+     |   +-->3      |
                       +--^+  ACD +-----+   |  +-------+
+---------------+          +------+         |
|Alt PLL        |                           |
|               +---------------------------+
+---------------+         PLL_EARLY
Quoted 1 line

Thanks for the diagram. Please also put it at the top of the driver file.

Will be added in the next spin.

Quoted 15 lines
Quoted 10 lines

The primary PLL is what drives the CPU clk, except for times when we are reprogramming the PLL itself (for rate changes) when we temporarily switch to an alternate PLL. A subsequent patch adds support to switch between primary and alternate PLL during rate changes.

The primary PLL operates on a single VCO range, between 600Mhz and 3Ghz. However the CPUs do support OPPs with frequencies between

300Mhz

Quoted 4 lines

and 600Mhz. In order to support running the CPUs at those frequencies we end up having to lock the PLL at twice the rate and drive the CPU clk via the PLL/2 output and SMUX.

Quoted 5 lines
Quoted 3 lines

So for frequencies above 600Mhz we follow the following path Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk and for frequencies between 300Mhz and 600Mhz we follow

Capitalize 'h' in units please.

OK

Quoted 28 lines
Quoted 28 lines

Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk Support for
this is added in a subsequent patch as well.

ACD stands for Adaptive Clock Distribution and is used to detect voltage droops. We do not add support for ACD as yet. This can be added at a later point as needed.

---
 drivers/clk/qcom/Kconfig        |   8 +
 drivers/clk/qcom/Makefile       |   1 +
 drivers/clk/qcom/clk-cpu-8996.c | 409
++++++++++++++++++++++++++++++++++++++++
 3 files changed, 418 insertions(+)
 create mode 100644 drivers/clk/qcom/clk-cpu-8996.c
drivers/clk/qcom/Kconfig index renamed from drivers/clk/qcom/Kconfig +0 -0

fbf4532..3274877 100644

drivers/clk/qcom/Kconfig +2 -0
@@ -226,3 +226,11 @@ config SPMI_PMIC_CLKDIV
          Technologies, Inc. SPMI PMIC. It configures the frequency of
          clkdiv outputs of the PMIC. These clocks are typically wired
          through alternate functions on GPIO pins.
+
+config MSM_APCC_8996
Quoted 8 lines

drivers/clk/qcom/Kconfig config SPMI_PMIC_CLKDIV · line 236

Quoted 6 lines
drivers/clk/qcom/Kconfig +6 -0
+       tristate "MSM8996 CPU Clock Controller"
+       depends on COMMON_CLK_QCOM
+       help
+         Support for the CPU clock controller on msm8996 devices.
+         Say Y if you want to support CPU clock scaling using CPUfreq
+         drivers for dyanmic power management.

Sort?

Will be changed in the next spin.

Quoted 12 lines

drivers/clk/qcom/Makefile obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o · line 36

Quoted 10 lines
drivers/clk/qcom/Makefile +1 -0
index 230332c..57b38ba 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
 obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+obj-$(CONFIG_MSM_APCC_8996) += clk-cpu-8996.o

This doesn't look sorted.

Will be changed in the next spin.

Quoted 16 lines
Quoted 16 lines
drivers/clk/qcom/Makefile +0 -0
 obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
 obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
 obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o diff --git

a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c new file mode 100644 index 0000000..42489f1

drivers/clk/qcom/clk-cpu-8996.c new file +7 -0
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 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
+ * only version 2 as published by the Free Software Foundation.
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 12

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+ *
+ * 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.
+ */

Can we get the SPDX tags here please?

Will be changed in the next spin.

Quoted 14 lines

drivers/clk/qcom/clk-cpu-8996.c line 14

Quoted 3 lines
drivers/clk/qcom/clk-cpu-8996.c new file +2 -0
+
+#include <linux/clk.h>

clk-provider.h?

drivers/clk/qcom/clk-cpu-8996.c line 19

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c new file +5 -0
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "clk-alpha-pll.h"

#include "clk-regmap.h"

Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 25

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+
+#define VCO(a, b, c) { \
+       .val = a,\
+       .min_freq = b,\
+       .max_freq = c,\
+}

Can this define go into whatever PLL header file defines the struct?

Will be changed in the next spin.

Quoted 15 lines

drivers/clk/qcom/clk-cpu-8996.c line 37

Quoted 13 lines
drivers/clk/qcom/clk-cpu-8996.c new file +12 -0
+
+#define DIV_2_INDEX            0
+#define PLL_INDEX              1
+#define ACD_INDEX              2
+#define ALT_INDEX              3
+
+static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
+       [PLL_OFF_L_VAL] = 0x04,
+       [PLL_OFF_ALPHA_VAL] = 0x08,
+       [PLL_OFF_USER_CTL] = 0x10,
+       [PLL_OFF_CONFIG_CTL] = 0x18,
+       [PLL_OFF_CONFIG_CTL_U] = 0x1C,

Please use lowercase hex throughout. Consistency is key!

Will be changed in the next spin.

Quoted 98 lines
Quoted 98 lines
drivers/clk/qcom/clk-cpu-8996.c new file +97 -0
+       [PLL_OFF_TEST_CTL] = 0x20,
+       [PLL_OFF_TEST_CTL_U] = 0x24,
+       [PLL_OFF_STATUS] = 0x28,
+};
+
+static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
+       [PLL_OFF_L_VAL] = 0x04,
+       [PLL_OFF_ALPHA_VAL] = 0x08,
+       [PLL_OFF_ALPHA_VAL_U] = 0x0c,
+       [PLL_OFF_USER_CTL] = 0x10,
+       [PLL_OFF_USER_CTL_U] = 0x14,
+       [PLL_OFF_CONFIG_CTL] = 0x18,
+       [PLL_OFF_TEST_CTL] = 0x20,
+       [PLL_OFF_TEST_CTL_U] = 0x24,
+       [PLL_OFF_STATUS] = 0x28,
+};
+
+/* PLLs */
+
+static const struct alpha_pll_config hfpll_config = {
+       .l = 60,
+       .config_ctl_val = 0x200d4828,
+       .config_ctl_hi_val = 0x006,
+       .pre_div_mask = BIT(12),
+       .post_div_mask = 0x3 << 8,
+       .main_output_mask = BIT(0),
+       .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_pll = {
+       .offset = 0x80000,
+       .regs = prim_pll_regs,
+       .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "perfcl_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_huayra_ops,
+       },
+};
+
+static struct clk_alpha_pll pwrcl_pll = {
+       .offset = 0x0,
+       .regs = prim_pll_regs,
+       .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pwrcl_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_huayra_ops,
+       },
+};
+
+static const struct pll_vco alt_pll_vco_modes[] = {
+       VCO(3,  250000000,  500000000),
+       VCO(2,  500000000,  750000000),
+       VCO(1,  750000000, 1000000000),
+       VCO(0, 1000000000, 2150400000), };
+
+static const struct alpha_pll_config altpll_config = {
+       .l = 16,
+       .vco_val = 0x3 << 20,
+       .vco_mask = 0x3 << 20,
+       .config_ctl_val = 0x4001051b,
+       .post_div_mask = 0x3 << 8,
+       .post_div_val = 0x1,
+       .main_output_mask = BIT(0),
+       .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_alt_pll = {
+       .offset = 0x80100,
+       .regs = alt_pll_regs,
+       .vco_table = alt_pll_vco_modes,
+       .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+       .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "perfcl_alt_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_hwfsm_ops,
+       },
+};
+
+static struct clk_alpha_pll pwrcl_alt_pll = {
+       .offset = 0x100,
+       .regs = alt_pll_regs,
+       .vco_table = alt_pll_vco_modes,
+       .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+       .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "pwrcl_alt_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_hwfsm_ops,
+       },
+};
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 141

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+
+/* Mux'es */
+
+struct clk_cpu_8996_mux {
+       u32     reg;
+       u32     shift;

u8 shift?

Will be changed in the next spin.

Quoted 4 lines

drivers/clk/qcom/clk-cpu-8996.c line 142

Quoted 2 lines
drivers/clk/qcom/clk-cpu-8996.c new file +1 -0
+       u32     width;

u8 width?

Will be changed in the next spin.

Quoted 17 lines

drivers/clk/qcom/clk-cpu-8996.c

Quoted 7 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+       struct clk_hw   *pll;
+       struct clk_regmap clkr;
+};
+
+static inline
+struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw

*hw) {

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c new file +9 -0
+       return container_of(to_clk_regmap(hw), struct
+clk_cpu_8996_mux, clkr); }
+
+static u8 clk_cpu_8996_mux_get_parent(struct clk_hw *hw) {
+       unsigned int val;
+       struct clk_regmap *clkr = to_clk_regmap(hw);
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       unsigned int mask = GENMASK(cpuclk->width - 1, 0);
+
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 165

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+       regmap_read(clkr->regmap, cpuclk->reg, &val);
+
+       val >>= cpuclk->shift;
+       val &= mask;
+
+       return val;

return val & mask;

struct clk_cpu_8996_mux *

Quoted 7 lines

drivers/clk/qcom/clk-cpu-8996.c line 155

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c new file +4 -0
+}
+
+static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index) {
+       unsigned int val;

u32 val?

Will be changed in the next spin.

Quoted 14 lines
Quoted 14 lines
drivers/clk/qcom/clk-cpu-8996.c new file +13 -0
+       struct clk_regmap *clkr = to_clk_regmap(hw);
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       unsigned int mask = GENMASK(cpuclk->width + cpuclk->shift - 1,
+                                   cpuclk->shift);
+
+       val = index;
+       val <<= cpuclk->shift;
+
+       return regmap_update_bits(clkr->regmap, cpuclk->reg, mask,
+val); }
+
+static int
+clk_cpu_8996_mux_determine_rate(struct clk_hw *hw, struct
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 189

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+clk_rate_request *req) {
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       struct clk_hw *parent = cpuclk->pll;
+
+       if (!cpuclk->pll)
+               return -EINVAL;

Does this happen?

On successful probe it shouldn't. May I omit pointer checks in this case? Future maintenance ma y change the flow.

Quoted 49 lines

drivers/clk/qcom/clk-cpu-8996.c line 192

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c new file +3 -0
+
+       req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
+       req->best_parent_hw = parent;

Is the parent index always the same? Perhaps just call clk_hw_get_parent_by_index() then instead of adding a pointer to the clk_cpu_8996_mux.

Quoted 8 lines
drivers/clk/qcom/clk-cpu-8996.c new file +8 -0
+
+       return 0;
+}
+
+const struct clk_ops clk_cpu_8996_mux_ops = {
+       .set_parent = clk_cpu_8996_mux_set_parent,
+       .get_parent = clk_cpu_8996_mux_get_parent,
+       .determine_rate = clk_cpu_8996_mux_determine_rate, };

[...]

Quoted 31 lines
drivers/clk/qcom/clk-cpu-8996.c new file +31 -0
+
+static struct clk_cpu_8996_mux pwrcl_pmux = {
+       .reg = 0x40,
+       .shift = 0,
+       .width = 2,
+       .pll = &pwrcl_pll.clkr.hw,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "pwrcl_pmux",
+               .parent_names = (const char *[]){
+                       "pwrcl_smux",
+                       "pwrcl_pll",
+                       "pwrcl_pll_acd",
+                       "pwrcl_alt_pll",
+               },
+               .num_parents = 4,
+               .ops = &clk_cpu_8996_mux_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+       },
+};
+
+static struct clk_cpu_8996_mux perfcl_pmux = {
+       .reg = 0x80040,
+       .shift = 0,
+       .width = 2,
+       .pll = &perfcl_pll.clkr.hw,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "perfcl_pmux",
+               .parent_names = (const char *[]){
+                       "perfcl_smux",
+                       "perfcl_pll",
+                       "perfcl_pll_acd",
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 269

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c new file +5 -0
+                       "perfcl_alt_pll",
+               },
+               .num_parents = 4,
+               .ops = &clk_cpu_8996_mux_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,

Not sure CLK_IS_CRITICAL is the right mode. Perhaps CLK_IGNORE_UNUSED for now? We don't want to force XO to stay on forever here.

Have to unit test this.

Quoted 16 lines
Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c new file +3 -0
+       },
+};
+

drivers/clk/qcom/clk-cpu-8996.c line 282

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+static const struct regmap_config cpu_msm8996_regmap_config = {
+       .reg_bits               = 32,
+       .reg_stride             = 4,
+       .val_bits               = 32,
+       .max_register           = 0x80210,
+       .fast_io                = true,
+       .val_format_endian      = REGMAP_ENDIAN_LITTLE,
+};
+
+static const struct of_device_id match_table[] = {

Move this next to driver structure and give it a more specific name.

Will be changed in the next spin.

Quoted 4 lines
Quoted 2 lines

+ { .compatible = "qcom-msm8996-apcc" },

Bad compatible? Should be qcom,msm8996-apcc?

The naming is per Rob Herring's requirement.

Quoted 17 lines
Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c new file +4 -0
+       {}
+};
+
+struct clk_regmap *clks[] = {

drivers/clk/qcom/clk-cpu-8996.c line 297

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+       /* PLLs */
+       &perfcl_pll.clkr,
+       &pwrcl_pll.clkr,
+       &perfcl_alt_pll.clkr,
+       &pwrcl_alt_pll.clkr,
+       /* MUXs */
+       &perfcl_smux.clkr,
+       &pwrcl_smux.clkr,
+       &perfcl_pmux.clkr,
+       &pwrcl_pmux.clkr,

Please drop useless comments inside this array.

Will be changed in the next spin.

Quoted 10 lines

drivers/clk/qcom/clk-cpu-8996.c line 303

Quoted 7 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+};
+
+struct clk_hw_clks {
+       unsigned int num;
+       struct clk_hw *hws[];
+};

Please just NULL terminate the list of clk_hw pointers, or keep the size around instead.

Will be changed in the next spin.

Quoted 15 lines

drivers/clk/qcom/clk-cpu-8996.c

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c new file +3 -0
+
+static int
+qcom_cpu_clk_msm8996_register_clks(struct device *dev, struct

clk_hw_clks *hws,

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+                                  struct regmap *regmap) {
+       int i, ret;
+
+       hws->hws[0] = clk_hw_register_fixed_factor(dev, "perfcl_pll_main",
+                                                  "perfcl_pll",
+                                                  CLK_SET_RATE_PARENT, 1, 2);
+       perfcl_smux.pll = hws->hws[0];
+
+       hws->hws[1] = clk_hw_register_fixed_factor(dev, "pwrcl_pll_main",
+                                                  "pwrcl_pll",
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 321

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c new file +4 -0
+                                                  CLK_SET_RATE_PARENT, 1, 2);
+       pwrcl_smux.pll = hws->hws[1];
+
+       hws->num = 2;

Maybe just open code the fixed factor clk registration? Then the devm_clk_hw_register() function can be used on those static structs to make removal simpler.

I will check this.

Quoted 17 lines
Quoted 17 lines
drivers/clk/qcom/clk-cpu-8996.c new file +16 -0
+
+       for (i = 0; i < ARRAY_SIZE(clks); i++) {
+               ret = devm_clk_register_regmap(dev, clks[i]);
+               if (ret)
+                       return ret;
+       }
+
+       clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
+       clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
+       clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
+       clk_alpha_pll_configure(&pwrcl_alt_pll, regmap,
+ &altpll_config);
+
+       return ret;
+}
+
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 342

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device
+*pdev) {
+       int ret;
+       void __iomem *base;
+       struct resource *res;
+       struct regmap *regmap_cpu;

Just call it regmap please.

Will be changed in the next spin.

Quoted 42 lines
Quoted 31 lines
drivers/clk/qcom/clk-cpu-8996.c new file +30 -0
+       struct clk_hw_clks *hws;
+       struct clk_hw_onecell_data *data;
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+
+       data = devm_kzalloc(dev, sizeof(*data) + 2 * sizeof(struct clk_hw *),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       hws = devm_kzalloc(dev, sizeof(*hws) + 2 * sizeof(struct clk_hw *),
+                          GFP_KERNEL);
+       if (!hws)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       regmap_cpu = devm_regmap_init_mmio(dev, base,
+                                          &cpu_msm8996_regmap_config);
+       if (IS_ERR(regmap_cpu))
+               return PTR_ERR(regmap_cpu);
+
+       ret = qcom_cpu_clk_msm8996_register_clks(dev, hws, regmap_cpu);
+       if (ret)
+               return ret;
+
+       data->hws[0] = &pwrcl_pmux.clkr.hw;

drivers/clk/qcom/clk-cpu-8996.c

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+       data->hws[1] = &perfcl_pmux.clkr.hw;
+
+       data->num = 2;
+
+       platform_set_drvdata(pdev, hws);
+
+       return of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+data); }
+
+static int qcom_cpu_clk_msm8996_driver_remove(struct

platform_device

Quoted 11 lines

drivers/clk/qcom/clk-cpu-8996.c line 391

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c new file +9 -0
+*pdev) {
+       int i;
+       struct device *dev = &pdev->dev;
+       struct clk_hw_clks *hws = platform_get_drvdata(pdev);
+
+       for (i = 0; i < hws->num; i++)
+               clk_hw_unregister_fixed_rate(hws->hws[i]);
+
+       of_clk_del_provider(dev->of_node);

Use devm_of_clk_add_hw_provider() instead.

Will be changed in the next spin.

Quoted 12 lines
Quoted 12 lines
drivers/clk/qcom/clk-cpu-8996.c new file +11 -0
+
+       return 0;
+}
+
+static struct platform_driver qcom_cpu_clk_msm8996_driver = {
+       .probe = qcom_cpu_clk_msm8996_driver_probe,
+       .remove = qcom_cpu_clk_msm8996_driver_remove,
+       .driver = {
+               .name = "qcom-msm8996-apcc",
+               .of_match_table = match_table,
+       },
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 408

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+};
+
+module_platform_driver(qcom_cpu_clk_msm8996_driver);
+
+MODULE_ALIAS("platform:msm8996-apcc");
+MODULE_DESCRIPTION("QCOM MSM8996 CPU clock Driver");

Not sure why Driver is capitalized and clock is not.

Will be changed in the next spin.

maintainer
#9 lore raw

PATCH v3 3/10 clk: qcom: Add CPU clock driver for msm8996

Quoting ilialin at codeaurora.org (2018-03-20 07:18:57)

Quoted 24 lines
Quoted 15 lines

From: Stephen Boyd <[email protected]>

Quoted 13 lines
drivers/clk/qcom/clk-cpu-8996.c new file +13 -0
+       struct clk_regmap *clkr = to_clk_regmap(hw);
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       unsigned int mask = GENMASK(cpuclk->width + cpuclk->shift - 1,
+                                   cpuclk->shift);
+
+       val = index;
+       val <<= cpuclk->shift;
+
+       return regmap_update_bits(clkr->regmap, cpuclk->reg, mask,
+val); }
+
+static int
+clk_cpu_8996_mux_determine_rate(struct clk_hw *hw, struct
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 189

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+clk_rate_request *req) {
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       struct clk_hw *parent = cpuclk->pll;
+
+       if (!cpuclk->pll)
+               return -EINVAL;

Does this happen?

Quoted 2 lines

On successful probe it shouldn't. May I omit pointer checks in this case? Future maintenance ma y change the flow.

Yes please omit useless checks.

Quoted 27 lines
Quoted 11 lines

drivers/clk/qcom/clk-cpu-8996.c line 192

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c new file +3 -0
+
+       req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
+       req->best_parent_hw = parent;

Is the parent index always the same? Perhaps just call clk_hw_get_parent_by_index() then instead of adding a pointer to the clk_cpu_8996_mux.

Quoted 15 lines

drivers/clk/qcom/clk-cpu-8996.c line 282

Quoted 13 lines
drivers/clk/qcom/clk-cpu-8996.c new file +13 -0
+       },
+};
+
+static const struct regmap_config cpu_msm8996_regmap_config = {
+       .reg_bits               = 32,
+       .reg_stride             = 4,
+       .val_bits               = 32,
+       .max_register           = 0x80210,
+       .fast_io                = true,
+       .val_format_endian      = REGMAP_ENDIAN_LITTLE,
+};
+
+static const struct of_device_id match_table[] = {

Move this next to driver structure and give it a more specific name.

Quoted 9 lines

Will be changed in the next spin.

Quoted 4 lines
Quoted 2 lines

+ { .compatible = "qcom-msm8996-apcc" },

Bad compatible? Should be qcom,msm8996-apcc?

The naming is per Rob Herring's requirement.

Hmm, maybe Rob made a typo?

#10 lore raw

PATCH v3 3/10 clk: qcom: Add CPU clock driver for msm8996

In reply to Stephen Boyd
Quoted 456 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Monday, March 19, 2018 19:37
To: Ilia Lin <[email protected]>; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; linux-clk at vger.kernel.org;
sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; ilialin at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: Re: [PATCH v3 03/10] clk: qcom: Add CPU clock driver for msm8996

Quoting Ilia Lin (2018-02-14 05:59:45)

Quoted 19 lines

From: Rajendra Nayak <[email protected]>

Each of the CPU clusters (Power and Perf) on msm8996 are clocked via 2 PLLs, a primary and alternate. There are also
2 Mux'es, a primary and secondary all connected together as shown below

                             +-------+
              XO             |       |
          +------------------>0      |
                             |       |
                   PLL/2     | SMUX  +----+
                     +------->1      |    |
                     |       |       |    |
                     |       +-------+    |    +-------+
                     |                    +---->0      |
                     |                         |       |
+---------------+    |             +----------->1      | CPU clk
|Primary PLL    +----+ PLL_EARLY   |           |       +------>
Quoted 8 lines
|               +------+-----------+    +------>2 PMUX |
+---------------+      |                |      |       |
                       |   +------+     |   +-->3      |
                       +--^+  ACD +-----+   |  +-------+
+---------------+          +------+         |
|Alt PLL        |                           |
|               +---------------------------+
+---------------+         PLL_EARLY

Thanks for the diagram. Please also put it at the top of the driver file.

Quoted 9 lines

The primary PLL is what drives the CPU clk, except for times when we are reprogramming the PLL itself (for rate changes) when we temporarily switch to an alternate PLL. A subsequent patch adds support to switch between primary and alternate PLL during rate changes.

The primary PLL operates on a single VCO range, between 600Mhz and 3Ghz. However the CPUs do support OPPs with frequencies between

300Mhz

Quoted 7 lines

and 600Mhz. In order to support running the CPUs at those frequencies we end up having to lock the PLL at twice the rate and drive the CPU clk via the PLL/2 output and SMUX.

So for frequencies above 600Mhz we follow the following path Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk and for frequencies between 300Mhz and 600Mhz we follow

Capitalize 'h' in units please.

Quoted 23 lines

Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk Support for
this is added in a subsequent patch as well.

ACD stands for Adaptive Clock Distribution and is used to detect voltage droops. We do not add support for ACD as yet. This can be added at a later point as needed.

---
 drivers/clk/qcom/Kconfig        |   8 +
 drivers/clk/qcom/Makefile       |   1 +
 drivers/clk/qcom/clk-cpu-8996.c | 409
++++++++++++++++++++++++++++++++++++++++
 3 files changed, 418 insertions(+)
 create mode 100644 drivers/clk/qcom/clk-cpu-8996.c
drivers/clk/qcom/Kconfig index renamed from drivers/clk/qcom/Kconfig +0 -0

fbf4532..3274877 100644

drivers/clk/qcom/Kconfig +0 -0
@@ -226,3 +226,11 @@ config SPMI_PMIC_CLKDIV
          Technologies, Inc. SPMI PMIC. It configures the frequency of

drivers/clk/qcom/Kconfig config SPMI_PMIC_CLKDIV · line 236

Quoted 10 lines
drivers/clk/qcom/Kconfig +8 -0
          clkdiv outputs of the PMIC. These clocks are typically wired
          through alternate functions on GPIO pins.
+
+config MSM_APCC_8996
+       tristate "MSM8996 CPU Clock Controller"
+       depends on COMMON_CLK_QCOM
+       help
+         Support for the CPU clock controller on msm8996 devices.
+         Say Y if you want to support CPU clock scaling using CPUfreq
+         drivers for dyanmic power management.

Sort?

drivers/clk/qcom/Makefile obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o · line 36

Quoted 9 lines
drivers/clk/qcom/Makefile +1 -0
index 230332c..57b38ba 100644
@@ -33,6 +33,7 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
 obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
 obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+obj-$(CONFIG_MSM_APCC_8996) += clk-cpu-8996.o

This doesn't look sorted.

Quoted 11 lines
drivers/clk/qcom/Makefile +0 -0
 obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
 obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
 obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o diff --git

a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c new file mode 100644 index 0000000..42489f1

drivers/clk/qcom/clk-cpu-8996.c new file +3 -0
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *

drivers/clk/qcom/clk-cpu-8996.c line 13

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+ * 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */

Can we get the SPDX tags here please?

drivers/clk/qcom/clk-cpu-8996.c line 14

Quoted 2 lines
drivers/clk/qcom/clk-cpu-8996.c new file +2 -0
+
+#include <linux/clk.h>

clk-provider.h?

drivers/clk/qcom/clk-cpu-8996.c line 19

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c new file +5 -0
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "clk-alpha-pll.h"

#include "clk-regmap.h"

drivers/clk/qcom/clk-cpu-8996.c line 25

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+
+#define VCO(a, b, c) { \
+       .val = a,\
+       .min_freq = b,\
+       .max_freq = c,\
+}

Can this define go into whatever PLL header file defines the struct?

drivers/clk/qcom/clk-cpu-8996.c line 37

Quoted 12 lines
drivers/clk/qcom/clk-cpu-8996.c new file +12 -0
+
+#define DIV_2_INDEX            0
+#define PLL_INDEX              1
+#define ACD_INDEX              2
+#define ALT_INDEX              3
+
+static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
+       [PLL_OFF_L_VAL] = 0x04,
+       [PLL_OFF_ALPHA_VAL] = 0x08,
+       [PLL_OFF_USER_CTL] = 0x10,
+       [PLL_OFF_CONFIG_CTL] = 0x18,
+       [PLL_OFF_CONFIG_CTL_U] = 0x1C,

Please use lowercase hex throughout. Consistency is key!

Quoted 93 lines
drivers/clk/qcom/clk-cpu-8996.c new file +93 -0
+       [PLL_OFF_TEST_CTL] = 0x20,
+       [PLL_OFF_TEST_CTL_U] = 0x24,
+       [PLL_OFF_STATUS] = 0x28,
+};
+
+static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
+       [PLL_OFF_L_VAL] = 0x04,
+       [PLL_OFF_ALPHA_VAL] = 0x08,
+       [PLL_OFF_ALPHA_VAL_U] = 0x0c,
+       [PLL_OFF_USER_CTL] = 0x10,
+       [PLL_OFF_USER_CTL_U] = 0x14,
+       [PLL_OFF_CONFIG_CTL] = 0x18,
+       [PLL_OFF_TEST_CTL] = 0x20,
+       [PLL_OFF_TEST_CTL_U] = 0x24,
+       [PLL_OFF_STATUS] = 0x28,
+};
+
+/* PLLs */
+
+static const struct alpha_pll_config hfpll_config = {
+       .l = 60,
+       .config_ctl_val = 0x200d4828,
+       .config_ctl_hi_val = 0x006,
+       .pre_div_mask = BIT(12),
+       .post_div_mask = 0x3 << 8,
+       .main_output_mask = BIT(0),
+       .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_pll = {
+       .offset = 0x80000,
+       .regs = prim_pll_regs,
+       .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "perfcl_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_huayra_ops,
+       },
+};
+
+static struct clk_alpha_pll pwrcl_pll = {
+       .offset = 0x0,
+       .regs = prim_pll_regs,
+       .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data){
+               .name = "pwrcl_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_huayra_ops,
+       },
+};
+
+static const struct pll_vco alt_pll_vco_modes[] = {
+       VCO(3,  250000000,  500000000),
+       VCO(2,  500000000,  750000000),
+       VCO(1,  750000000, 1000000000),
+       VCO(0, 1000000000, 2150400000), };
+
+static const struct alpha_pll_config altpll_config = {
+       .l = 16,
+       .vco_val = 0x3 << 20,
+       .vco_mask = 0x3 << 20,
+       .config_ctl_val = 0x4001051b,
+       .post_div_mask = 0x3 << 8,
+       .post_div_val = 0x1,
+       .main_output_mask = BIT(0),
+       .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_alt_pll = {
+       .offset = 0x80100,
+       .regs = alt_pll_regs,
+       .vco_table = alt_pll_vco_modes,
+       .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+       .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "perfcl_alt_pll",
+               .parent_names = (const char *[]){ "xo" },
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_hwfsm_ops,
+       },
+};
+
+static struct clk_alpha_pll pwrcl_alt_pll = {
+       .offset = 0x100,
+       .regs = alt_pll_regs,
+       .vco_table = alt_pll_vco_modes,
+       .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+       .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "pwrcl_alt_pll",
+               .parent_names = (const char *[]){ "xo" },

drivers/clk/qcom/clk-cpu-8996.c line 141

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+               .num_parents = 1,
+               .ops = &clk_alpha_pll_hwfsm_ops,
+       },
+};
+
+/* Mux'es */
+
+struct clk_cpu_8996_mux {
+       u32     reg;
+       u32     shift;

u8 shift?

drivers/clk/qcom/clk-cpu-8996.c line 142

Quoted 1 line
drivers/clk/qcom/clk-cpu-8996.c new file +1 -0
+       u32     width;

u8 width?

drivers/clk/qcom/clk-cpu-8996.c

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+       struct clk_hw   *pll;
+       struct clk_regmap clkr;
+};
+
+static inline
+struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw

*hw) {

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c new file +5 -0
+       return container_of(to_clk_regmap(hw), struct
+clk_cpu_8996_mux, clkr); }
+
+static u8 clk_cpu_8996_mux_get_parent(struct clk_hw *hw) {
+       unsigned int val;

drivers/clk/qcom/clk-cpu-8996.c line 165

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+       struct clk_regmap *clkr = to_clk_regmap(hw);
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       unsigned int mask = GENMASK(cpuclk->width - 1, 0);
+
+       regmap_read(clkr->regmap, cpuclk->reg, &val);
+
+       val >>= cpuclk->shift;
+       val &= mask;
+
+       return val;

return val & mask;

drivers/clk/qcom/clk-cpu-8996.c line 155

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c new file +4 -0
+}
+
+static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index) {
+       unsigned int val;

u32 val?

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c new file +9 -0
+       struct clk_regmap *clkr = to_clk_regmap(hw);
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       unsigned int mask = GENMASK(cpuclk->width + cpuclk->shift - 1,
+                                   cpuclk->shift);
+
+       val = index;
+       val <<= cpuclk->shift;
+
+       return regmap_update_bits(clkr->regmap, cpuclk->reg, mask,

drivers/clk/qcom/clk-cpu-8996.c line 189

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+val); }
+
+static int
+clk_cpu_8996_mux_determine_rate(struct clk_hw *hw, struct
+clk_rate_request *req) {
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+       struct clk_hw *parent = cpuclk->pll;
+
+       if (!cpuclk->pll)
+               return -EINVAL;

Does this happen?

drivers/clk/qcom/clk-cpu-8996.c line 192

Quoted 3 lines
drivers/clk/qcom/clk-cpu-8996.c new file +3 -0
+
+       req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
+       req->best_parent_hw = parent;

Is the parent index always the same? Perhaps just call clk_hw_get_parent_by_index() then instead of adding a pointer to the clk_cpu_8996_mux.

Quoted 8 lines
drivers/clk/qcom/clk-cpu-8996.c new file +8 -0
+
+       return 0;
+}
+
+const struct clk_ops clk_cpu_8996_mux_ops = {
+       .set_parent = clk_cpu_8996_mux_set_parent,
+       .get_parent = clk_cpu_8996_mux_get_parent,
+       .determine_rate = clk_cpu_8996_mux_determine_rate, };

[...]

Quoted 26 lines
drivers/clk/qcom/clk-cpu-8996.c new file +26 -0
+
+static struct clk_cpu_8996_mux pwrcl_pmux = {
+       .reg = 0x40,
+       .shift = 0,
+       .width = 2,
+       .pll = &pwrcl_pll.clkr.hw,
+       .clkr.hw.init = &(struct clk_init_data) {
+               .name = "pwrcl_pmux",
+               .parent_names = (const char *[]){
+                       "pwrcl_smux",
+                       "pwrcl_pll",
+                       "pwrcl_pll_acd",
+                       "pwrcl_alt_pll",
+               },
+               .num_parents = 4,
+               .ops = &clk_cpu_8996_mux_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+       },
+};
+
+static struct clk_cpu_8996_mux perfcl_pmux = {
+       .reg = 0x80040,
+       .shift = 0,
+       .width = 2,
+       .pll = &perfcl_pll.clkr.hw,
+       .clkr.hw.init = &(struct clk_init_data) {

drivers/clk/qcom/clk-cpu-8996.c line 269

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+               .name = "perfcl_pmux",
+               .parent_names = (const char *[]){
+                       "perfcl_smux",
+                       "perfcl_pll",
+                       "perfcl_pll_acd",
+                       "perfcl_alt_pll",
+               },
+               .num_parents = 4,
+               .ops = &clk_cpu_8996_mux_ops,
+               .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,

Not sure CLK_IS_CRITICAL is the right mode. Perhaps CLK_IGNORE_UNUSED for now? We don't want to force XO to stay on forever here.

drivers/clk/qcom/clk-cpu-8996.c line 282

Quoted 13 lines
drivers/clk/qcom/clk-cpu-8996.c new file +13 -0
+       },
+};
+
+static const struct regmap_config cpu_msm8996_regmap_config = {
+       .reg_bits               = 32,
+       .reg_stride             = 4,
+       .val_bits               = 32,
+       .max_register           = 0x80210,
+       .fast_io                = true,
+       .val_format_endian      = REGMAP_ENDIAN_LITTLE,
+};
+
+static const struct of_device_id match_table[] = {

Move this next to driver structure and give it a more specific name.

Quoted 1 line

+ { .compatible = "qcom-msm8996-apcc" },

Bad compatible? Should be qcom,msm8996-apcc?

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c new file +4 -0
+       {}
+};
+
+struct clk_regmap *clks[] = {

drivers/clk/qcom/clk-cpu-8996.c line 297

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+       /* PLLs */
+       &perfcl_pll.clkr,
+       &pwrcl_pll.clkr,
+       &perfcl_alt_pll.clkr,
+       &pwrcl_alt_pll.clkr,
+       /* MUXs */
+       &perfcl_smux.clkr,
+       &pwrcl_smux.clkr,
+       &perfcl_pmux.clkr,
+       &pwrcl_pmux.clkr,

Please drop useless comments inside this array.

drivers/clk/qcom/clk-cpu-8996.c line 303

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c new file +6 -0
+};
+
+struct clk_hw_clks {
+       unsigned int num;
+       struct clk_hw *hws[];
+};

Please just NULL terminate the list of clk_hw pointers, or keep the size around instead.

drivers/clk/qcom/clk-cpu-8996.c

Quoted 3 lines
drivers/clk/qcom/clk-cpu-8996.c new file +3 -0
+
+static int
+qcom_cpu_clk_msm8996_register_clks(struct device *dev, struct

clk_hw_clks *hws,

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+                                  struct regmap *regmap) {
+       int i, ret;
+
+       hws->hws[0] = clk_hw_register_fixed_factor(dev, "perfcl_pll_main",
+                                                  "perfcl_pll",
+                                                  CLK_SET_RATE_PARENT, 1, 2);
+       perfcl_smux.pll = hws->hws[0];
+
+       hws->hws[1] = clk_hw_register_fixed_factor(dev, "pwrcl_pll_main",
+                                                  "pwrcl_pll",
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 321

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c new file +4 -0
+                                                  CLK_SET_RATE_PARENT, 1, 2);
+       pwrcl_smux.pll = hws->hws[1];
+
+       hws->num = 2;

Maybe just open code the fixed factor clk registration? Then the devm_clk_hw_register() function can be used on those static structs to make removal simpler.

I will have to change the clk_hw_unregister_fixed_rate() as well then, right? This will be an API change.

Quoted 98 lines
Quoted 13 lines
drivers/clk/qcom/clk-cpu-8996.c new file +12 -0
+
+       for (i = 0; i < ARRAY_SIZE(clks); i++) {
+               ret = devm_clk_register_regmap(dev, clks[i]);
+               if (ret)
+                       return ret;
+       }
+
+       clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
+       clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
+       clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
+       clk_alpha_pll_configure(&pwrcl_alt_pll, regmap,
+ &altpll_config);

drivers/clk/qcom/clk-cpu-8996.c line 342

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+
+       return ret;
+}
+
+static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device
+*pdev) {
+       int ret;
+       void __iomem *base;
+       struct resource *res;
+       struct regmap *regmap_cpu;

Just call it regmap please.

Quoted 30 lines
drivers/clk/qcom/clk-cpu-8996.c new file +30 -0
+       struct clk_hw_clks *hws;
+       struct clk_hw_onecell_data *data;
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+
+       data = devm_kzalloc(dev, sizeof(*data) + 2 * sizeof(struct clk_hw *),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       hws = devm_kzalloc(dev, sizeof(*hws) + 2 * sizeof(struct clk_hw *),
+                          GFP_KERNEL);
+       if (!hws)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       regmap_cpu = devm_regmap_init_mmio(dev, base,
+                                          &cpu_msm8996_regmap_config);
+       if (IS_ERR(regmap_cpu))
+               return PTR_ERR(regmap_cpu);
+
+       ret = qcom_cpu_clk_msm8996_register_clks(dev, hws, regmap_cpu);
+       if (ret)
+               return ret;
+
+       data->hws[0] = &pwrcl_pmux.clkr.hw;

drivers/clk/qcom/clk-cpu-8996.c

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+       data->hws[1] = &perfcl_pmux.clkr.hw;
+
+       data->num = 2;
+
+       platform_set_drvdata(pdev, hws);
+
+       return of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+data); }
+
+static int qcom_cpu_clk_msm8996_driver_remove(struct

platform_device

drivers/clk/qcom/clk-cpu-8996.c line 391

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c new file +9 -0
+*pdev) {
+       int i;
+       struct device *dev = &pdev->dev;
+       struct clk_hw_clks *hws = platform_get_drvdata(pdev);
+
+       for (i = 0; i < hws->num; i++)
+               clk_hw_unregister_fixed_rate(hws->hws[i]);
+
+       of_clk_del_provider(dev->of_node);

Use devm_of_clk_add_hw_provider() instead.

Quoted 7 lines
drivers/clk/qcom/clk-cpu-8996.c new file +7 -0
+
+       return 0;
+}
+
+static struct platform_driver qcom_cpu_clk_msm8996_driver = {
+       .probe = qcom_cpu_clk_msm8996_driver_probe,
+       .remove = qcom_cpu_clk_msm8996_driver_remove,

drivers/clk/qcom/clk-cpu-8996.c line 408

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c new file +10 -0
+       .driver = {
+               .name = "qcom-msm8996-apcc",
+               .of_match_table = match_table,
+       },
+};
+
+module_platform_driver(qcom_cpu_clk_msm8996_driver);
+
+MODULE_ALIAS("platform:msm8996-apcc");
+MODULE_DESCRIPTION("QCOM MSM8996 CPU clock Driver");

Not sure why Driver is capitalized and clock is not.

maintainer
#11 lore raw

PATCH v3 3/10 clk: qcom: Add CPU clock driver for msm8996

Quoting ilialin at codeaurora.org (2018-03-22 03:47:30)

Quoted 2 lines

I will have to change the clk_hw_unregister_fixed_rate() as well then, right? This will be an API change.

You won't need to unregister anything? devm will take care of it.

author
#12 lore raw

PATCH v3 4/10 clk: qcom: Add DT bindings for CPU clock driver for msm8996

In reply to Ilia Lin
---
 Documentation/devicetree/bindings/clock/qcom,kryocc.txt | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/qcom,kryocc.txt
Documentation/devicetree/bindings/clock/qcom,kryocc.txt new file +17 -0
new file mode 100644
index 0000000..e7cf15a
@@ -0,0 +1,17 @@
+Qualcomm CPUSS clock controller for Kryo CPUs
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+
+			"qcom-msm8996-apcc"
+
+- reg : shall contain base register location and length
+- #clock-cells : shall contain 1
+
+Example:
+	kryocc: clock-controller at 6400000 {
+		compatible = "qcom-msm8996-apcc";
+		reg = <0x6400000 0x90000>;
+		#clock-cells = <1>;
+	};
Signature · 1 line
1.9.1
maintainer
#13 lore raw

PATCH v3 4/10 clk: qcom: Add DT bindings for CPU clock driver for msm8996

Quoted 5 lines · Ilia Lin
---
 Documentation/devicetree/bindings/clock/qcom,kryocc.txt | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/qcom,kryocc.txt
maintainer
#14 lore raw

PATCH v3 4/10 clk: qcom: Add DT bindings for CPU clock driver for msm8996

In reply to Ilia Lin

Quoting Ilia Lin (2018-02-14 05:59:46)

Quoted 12 lines
---
 Documentation/devicetree/bindings/clock/qcom,kryocc.txt | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/qcom,kryocc.txt
Documentation/devicetree/bindings/clock/qcom,kryocc.txt new file +0 -0
new file mode 100644
index 0000000..e7cf15a

Documentation/devicetree/bindings/clock/qcom,kryocc.txt line 7

Quoted 7 lines
Documentation/devicetree/bindings/clock/qcom,kryocc.txt new file +7 -0
@@ -0,0 +1,17 @@
+Qualcomm CPUSS clock controller for Kryo CPUs
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+
+                       "qcom-msm8996-apcc"

Do you mean qcom,msm8996-apcc?

Rob?

#15 lore raw

PATCH v3 4/10 clk: qcom: Add DT bindings for CPU clock driver for msm8996

Quoted 26 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Monday, March 19, 2018 19:47
To: Ilia Lin <[email protected]>; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; linux-clk at vger.kernel.org;
sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; ilialin at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: Re: [PATCH v3 04/10] clk: qcom: Add DT bindings for CPU clock driver for msm8996

Quoting Ilia Lin (2018-02-14 05:59:46)

Quoted 3 lines
---
 Documentation/devicetree/bindings/clock/qcom,kryocc.txt | 17

+++++++++++++++++

Quoted 2 lines
 1 file changed, 17 insertions(+)
 create mode 100644

Documentation/devicetree/bindings/clock/qcom,kryocc.txt

Review

Quoted 2 lines
(quoted diff) +0 -0

b/Documentation/devicetree/bindings/clock/qcom,kryocc.txt

Quoted 14 lines

Documentation/devicetree/bindings/clock/qcom,kryocc.txt line 7

Quoted 12 lines

new file mode 100644
index 0000000..e7cf15a

Documentation/devicetree/bindings/clock/qcom,kryocc.txt new file +7 -0
@@ -0,0 +1,17 @@
+Qualcomm CPUSS clock controller for Kryo CPUs
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+
+                       "qcom-msm8996-apcc"

Do you mean qcom,msm8996-apcc?

The naming is per Rob's requirement.

Quoted 2 lines

Rob?

author
#16 lore raw

PATCH v3 5/10 clk: qcom: cpu-8996: Add support to switch to alternate PLL

In reply to Ilia Lin

From: Rajendra Nayak <[email protected]>

Each of the CPU clusters on msm8996 and powered via a primary PLL and a secondary PLL. The primary PLL is what drivers the CPU clk, except for times when we are reprogramming the PLL itself, when we temporarily switch to an alternate PLL. Use clock rate change notifiers to support this.

---
 drivers/clk/qcom/clk-cpu-8996.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)
drivers/clk/qcom/clk-cpu-8996.c +35 -0
index 42489f1..75bd014 100644
@@ -140,10 +140,14 @@ struct clk_cpu_8996_mux {
 	u32	reg;
 	u32	shift;
 	u32	width;
+	struct notifier_block nb;
 	struct clk_hw	*pll;
 	struct clk_regmap clkr;
 };
 
+#define to_clk_cpu_8996_mux_nb(_nb) \
+	container_of(_nb, struct clk_cpu_8996_mux, nb)
+
 static inline
 struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)
 {
@@ -194,6 +198,27 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
 	return 0;
 }
 
+int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+			void *data)
+{
+	int ret;
+	struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb);
+
+	switch (event) {
+	case PRE_RATE_CHANGE:
+		ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
+		break;
+	case POST_RATE_CHANGE:
+		ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, PLL_INDEX);
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+
+	return notifier_from_errno(ret);
+};
+
 const struct clk_ops clk_cpu_8996_mux_ops = {
 	.set_parent = clk_cpu_8996_mux_set_parent,
 	.get_parent = clk_cpu_8996_mux_get_parent,
@@ -237,6 +262,7 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
 	.shift = 0,
 	.width = 2,
 	.pll = &pwrcl_pll.clkr.hw,
+	.nb.notifier_call = cpu_clk_notifier_cb,
 	.clkr.hw.init = &(struct clk_init_data) {
 		.name = "pwrcl_pmux",
 		.parent_names = (const char *[]){
@@ -256,6 +282,7 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
 	.shift = 0,
 	.width = 2,
 	.pll = &perfcl_pll.clkr.hw,
+	.nb.notifier_call = cpu_clk_notifier_cb,
 	.clkr.hw.init = &(struct clk_init_data) {
 		.name = "perfcl_pmux",
 		.parent_names = (const char *[]){
@@ -331,6 +358,14 @@ struct clk_hw_clks {
 	clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
 	clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
 
+	ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
+	if (ret)
+		return ret;
+
+	ret = clk_notifier_register(perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb);
+	if (ret)
+		return ret;
+
 	return ret;
 }
 
Signature · 1 line
1.9.1
maintainer
#17 lore raw

PATCH v3 5/10 clk: qcom: cpu-8996: Add support to switch to alternate PLL

Quoting Ilia Lin (2018-02-14 05:59:47)

Quoted 3 lines

From: Rajendra Nayak <[email protected]>

Each of the CPU clusters on msm8996 and powered via a primary

s/and/are/

Quoted 1 line

PLL and a secondary PLL. The primary PLL is what drivers the

s/drivers/drives/

I make the same typo all the time!

Quoted 75 lines

CPU clk, except for times when we are reprogramming the PLL itself, when we temporarily switch to an alternate PLL. Use clock rate change notifiers to support this.

---
 drivers/clk/qcom/clk-cpu-8996.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)
drivers/clk/qcom/clk-cpu-8996.c +27 -0
index 42489f1..75bd014 100644
@@ -140,10 +140,14 @@ struct clk_cpu_8996_mux {
        u32     reg;
        u32     shift;
        u32     width;
+       struct notifier_block nb;
        struct clk_hw   *pll;
        struct clk_regmap clkr;
 };
 
+#define to_clk_cpu_8996_mux_nb(_nb) \
+       container_of(_nb, struct clk_cpu_8996_mux, nb)
+
 static inline
 struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)
 {
@@ -194,6 +198,27 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
        return 0;
 }
 
+int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+                       void *data)
+{
+       int ret;
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb);
+
+       switch (event) {
+       case PRE_RATE_CHANGE:
+               ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
+               break;
+       case POST_RATE_CHANGE:
+               ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, PLL_INDEX);
+               break;
+       default:
+               ret = 0;
+               break;
+       }
+
+       return notifier_from_errno(ret);
+};
+
 const struct clk_ops clk_cpu_8996_mux_ops = {
        .set_parent = clk_cpu_8996_mux_set_parent,
        .get_parent = clk_cpu_8996_mux_get_parent,
@@ -237,6 +262,7 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
        .shift = 0,
        .width = 2,
        .pll = &pwrcl_pll.clkr.hw,
+       .nb.notifier_call = cpu_clk_notifier_cb,
        .clkr.hw.init = &(struct clk_init_data) {
                .name = "pwrcl_pmux",
                .parent_names = (const char *[]){
@@ -256,6 +282,7 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
        .shift = 0,
        .width = 2,
        .pll = &perfcl_pll.clkr.hw,
+       .nb.notifier_call = cpu_clk_notifier_cb,
        .clkr.hw.init = &(struct clk_init_data) {
                .name = "perfcl_pmux",
                .parent_names = (const char *[]){
@@ -331,6 +358,14 @@ struct clk_hw_clks {
        clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 368

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c +8 -0
        clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
 
+       ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
+       if (ret)
+               return ret;
+
+       ret = clk_notifier_register(perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb);
+       if (ret)
+               return ret;
+

Please resend this with the other patches that need rework.

#18 lore raw

PATCH v3 5/10 clk: qcom: cpu-8996: Add support to switch to alternate PLL

Will be fixed and respinned.

Quoted 118 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Monday, March 19, 2018 19:48
To: Ilia Lin <[email protected]>; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; linux-clk at vger.kernel.org;
sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; ilialin at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: Re: [PATCH v3 05/10] clk: qcom: cpu-8996: Add support to switch to alternate PLL

Quoting Ilia Lin (2018-02-14 05:59:47)

Quoted 3 lines

From: Rajendra Nayak <[email protected]>

Each of the CPU clusters on msm8996 and powered via a primary

s/and/are/

Quoted 1 line

PLL and a secondary PLL. The primary PLL is what drivers the

s/drivers/drives/

I make the same typo all the time!

Quoted 19 lines

CPU clk, except for times when we are reprogramming the PLL itself, when we temporarily switch to an alternate PLL.
Use clock rate change notifiers to support this.

---
 drivers/clk/qcom/clk-cpu-8996.c | 35
+++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)
(quoted diff) +0 -0

b/drivers/clk/qcom/clk-cpu-8996.c index 42489f1..75bd014 100644

drivers/clk/qcom/clk-cpu-8996.c +0 -0
@@ -140,10 +140,14 @@ struct clk_cpu_8996_mux {
        u32     reg;
        u32     shift;
        u32     width;

drivers/clk/qcom/clk-cpu-8996.c struct clk_cpu_8996_mux { · line 152

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c +4 -0
+       struct notifier_block nb;
        struct clk_hw   *pll;
        struct clk_regmap clkr;
 };
 
+#define to_clk_cpu_8996_mux_nb(_nb) \
+       container_of(_nb, struct clk_cpu_8996_mux, nb)
+
 static inline
 struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)

{

drivers/clk/qcom/clk-cpu-8996.c static int clk_cpu_8996_mux_set_parent(struct

Quoted 1 line
drivers/clk/qcom/clk-cpu-8996.c +0 -0
@@ -194,6 +198,27 @@ static int clk_cpu_8996_mux_set_parent(struct

clk_hw *hw, u8 index)

drivers/clk/qcom/clk-cpu-8996.c static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)

Quoted 12 lines
drivers/clk/qcom/clk-cpu-8996.c +9 -0
        return 0;
 }
 
+int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+                       void *data)
+{
+       int ret;
+       struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb);
+
+       switch (event) {
+       case PRE_RATE_CHANGE:
+               ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,

ALT_INDEX);

drivers/clk/qcom/clk-cpu-8996.c static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)

Quoted 3 lines
drivers/clk/qcom/clk-cpu-8996.c +3 -0
+               break;
+       case POST_RATE_CHANGE:
+               ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,

PLL_INDEX);

Quoted 32 lines
drivers/clk/qcom/clk-cpu-8996.c +8 -0
+               break;
+       default:
+               ret = 0;
+               break;
+       }
+
+       return notifier_from_errno(ret); };
+
 const struct clk_ops clk_cpu_8996_mux_ops = {
        .set_parent = clk_cpu_8996_mux_set_parent,
        .get_parent = clk_cpu_8996_mux_get_parent, @@ -237,6 +262,7 @@

static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)

        .shift = 0,
        .width = 2,
        .pll = &pwrcl_pll.clkr.hw,
+       .nb.notifier_call = cpu_clk_notifier_cb,
        .clkr.hw.init = &(struct clk_init_data) {
                .name = "pwrcl_pmux",
                .parent_names = (const char *[]){ @@ -256,6 +282,7 @@
static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
        .shift = 0,
        .width = 2,
        .pll = &perfcl_pll.clkr.hw,
+       .nb.notifier_call = cpu_clk_notifier_cb,
        .clkr.hw.init = &(struct clk_init_data) {
                .name = "perfcl_pmux",
                .parent_names = (const char *[]){ @@ -331,6 +358,14 @@
struct clk_hw_clks {
        clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
        clk_alpha_pll_configure(&pwrcl_alt_pll, regmap,

&altpll_config);

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks {

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
+       ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
+       if (ret)
+               return ret;
+
+       ret = clk_notifier_register(perfcl_pmux.clkr.hw.clk,

&perfcl_pmux.nb);

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 364

Quoted 3 lines
drivers/clk/qcom/clk-cpu-8996.c +3 -0
+       if (ret)
+               return ret;
+

Please resend this with the other patches that need rework.

author
#19 lore raw

PATCH v3 6/10 clk: qcom: cpu-8996: Add support to switch below 600Mhz

In reply to Ilia Lin

From: Rajendra Nayak <[email protected]>

The CPU clock controllers primary PLL operates on a single VCO range, between 600Mhz and 3Ghz. However the CPUs do support OPPs with frequencies between 300Mhz and 600Mhz. In order to support running the CPUs at those frequencies we end up having to lock the PLL at twice the rate and drive the CPU clk via the PLL/2 output and SMUX.

So for frequencies above 600Mhz we follow the following path
Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
and for frequencies between 300Mhz and 600Mhz we follow
Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk

---
 drivers/clk/qcom/clk-cpu-8996.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)
drivers/clk/qcom/clk-cpu-8996.c +21 -3
index 75bd014..854f327 100644
@@ -28,6 +28,7 @@
 #define PLL_INDEX		1
 #define ACD_INDEX		2
 #define ALT_INDEX		3
+#define DIV_2_THRESHOLD		600000000
 
 static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
        [PLL_OFF_L_VAL] = 0x04,
@@ -56,10 +57,11 @@
 
 static const struct alpha_pll_config hfpll_config = {
 	.l = 60,
-	.config_ctl_val = 0x200d4828,
+	.config_ctl_val = 0x200D4AA8,
 	.config_ctl_hi_val = 0x006,
 	.pre_div_mask = BIT(12),
 	.post_div_mask = 0x3 << 8,
+	.post_div_val = 0x1 << 8,
 	.main_output_mask = BIT(0),
 	.early_output_mask = BIT(3),
 };
@@ -101,7 +103,7 @@
 	.vco_mask = 0x3 << 20,
 	.config_ctl_val = 0x4001051b,
 	.post_div_mask = 0x3 << 8,
-	.post_div_val = 0x1,
+	.post_div_val = 0x1 << 8,
 	.main_output_mask = BIT(0),
 	.early_output_mask = BIT(3),
 };
@@ -142,6 +144,7 @@ struct clk_cpu_8996_mux {
 	u32	width;
 	struct notifier_block nb;
 	struct clk_hw	*pll;
+	struct clk_hw	*pll_div_2;
 	struct clk_regmap clkr;
 };
 
@@ -192,6 +195,13 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
 	if (!cpuclk->pll)
 		return -EINVAL;
 
+	if (cpuclk->pll_div_2 && req->rate < DIV_2_THRESHOLD) {
+		if (req->rate < (DIV_2_THRESHOLD / 2))
+			return -EINVAL;
+
+		parent = cpuclk->pll_div_2;
+	}
+
 	req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
 	req->best_parent_hw = parent;
 
@@ -203,13 +213,19 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 {
 	int ret;
 	struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb);
+	struct clk_notifier_data *cnd = data;
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
 		ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
 		break;
 	case POST_RATE_CHANGE:
-		ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, PLL_INDEX);
+		if (cnd->new_rate < DIV_2_THRESHOLD)
+			ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
+							  DIV_2_INDEX);
+		else
+			ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
+							  PLL_INDEX);
 		break;
 	default:
 		ret = 0;
@@ -262,6 +278,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 	.shift = 0,
 	.width = 2,
 	.pll = &pwrcl_pll.clkr.hw,
+	.pll_div_2 = &pwrcl_smux.clkr.hw,
 	.nb.notifier_call = cpu_clk_notifier_cb,
 	.clkr.hw.init = &(struct clk_init_data) {
 		.name = "pwrcl_pmux",
@@ -282,6 +299,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 	.shift = 0,
 	.width = 2,
 	.pll = &perfcl_pll.clkr.hw,
+	.pll_div_2 = &perfcl_smux.clkr.hw,
 	.nb.notifier_call = cpu_clk_notifier_cb,
 	.clkr.hw.init = &(struct clk_init_data) {
 		.name = "perfcl_pmux",
Signature · 1 line
1.9.1
maintainer
#20 lore raw

PATCH v3 6/10 clk: qcom: cpu-8996: Add support to switch below 600Mhz

Quoting Ilia Lin (2018-02-14 05:59:48)

Quoted 3 lines

From: Rajendra Nayak <[email protected]>

The CPU clock controllers primary PLL operates on a single VCO range,

s/controllers/controller's/

Quoted 2 lines

between 600Mhz and 3Ghz. However the CPUs do support OPPs with frequencies between 300Mhz and 600Mhz. In order to support running the

capitalize 'h' in units please.

Quoted 10 lines

CPUs at those frequencies we end up having to lock the PLL at twice the rate and drive the CPU clk via the PLL/2 output and SMUX.

So for frequencies above 600Mhz we follow the following path
Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
and for frequencies between 300Mhz and 600Mhz we follow
Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk

Rest looks ok, please resend.

author
#21 lore raw

PATCH v3 7/10 clk: qcom: clk-cpu-8996: Prepare PLLs on probe

In reply to Ilia Lin

The PLLs must be prepared enabled during the probe to be accessible by the OPPs. Otherwise an OPP may switch to non-enabled clock.

---
 drivers/clk/qcom/clk-cpu-8996.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/clk/qcom/clk-cpu-8996.c +13 -1
index 854f327..b0a3b73 100644
@@ -15,7 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
-
+#include <linux/clk-provider.h>
 #include "clk-alpha-pll.h"
 
 #define VCO(a, b, c) { \
@@ -376,6 +376,18 @@ struct clk_hw_clks {
 	clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
 	clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
 
+	/* Enable all PLLs and alt PLLs */
+	clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
+	clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
+	clk_prepare_enable(pwrcl_pll.clkr.hw.clk);
+	clk_prepare_enable(perfcl_pll.clkr.hw.clk);
+
+	/* Set initial boot frequencies for power/perf PLLs */
+	clk_set_rate(pwrcl_alt_pll.clkr.hw.clk, 652800000);
+	clk_set_rate(perfcl_alt_pll.clkr.hw.clk, 652800000);
+	clk_set_rate(pwrcl_pll.clkr.hw.clk, 652800000);
+	clk_set_rate(perfcl_pll.clkr.hw.clk, 652800000);
+
 	ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
 	if (ret)
 		return ret;
Signature · 1 line
1.9.1
maintainer
#22 lore raw

PATCH v3 7/10 clk: qcom: clk-cpu-8996: Prepare PLLs on probe

Quoting Ilia Lin (2018-02-14 05:59:49)

Quoted 3 lines

The PLLs must be prepared enabled during the probe to be accessible by the OPPs. Otherwise an OPP may switch to non-enabled clock.

Sounds like an OPP problem.

Quoted 11 lines
---
 drivers/clk/qcom/clk-cpu-8996.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/clk/qcom/clk-cpu-8996.c +0 -0
index 854f327..b0a3b73 100644

drivers/clk/qcom/clk-cpu-8996.c line 18

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +1 -1
@@ -15,7 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
-
+#include <linux/clk-provider.h>

Please leave a newline between linux/* and local includes.

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 383

Quoted 12 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
 #include "clk-alpha-pll.h"
 
 #define VCO(a, b, c) { \
@@ -376,6 +376,18 @@ struct clk_hw_clks {
        clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
        clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
 
+       /* Enable all PLLs and alt PLLs */
+       clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
+       clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
+       clk_prepare_enable(pwrcl_pll.clkr.hw.clk);
+       clk_prepare_enable(perfcl_pll.clkr.hw.clk);

And this can't be done by the cpufreq-dt driver?

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 389

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c +6 -0
+
+       /* Set initial boot frequencies for power/perf PLLs */
+       clk_set_rate(pwrcl_alt_pll.clkr.hw.clk, 652800000);
+       clk_set_rate(perfcl_alt_pll.clkr.hw.clk, 652800000);
+       clk_set_rate(pwrcl_pll.clkr.hw.clk, 652800000);
+       clk_set_rate(perfcl_pll.clkr.hw.clk, 652800000);

We have assigned rates in DT for this.

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c +1 -0
+
        ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
        if (ret)
                return ret;
#23 lore raw

PATCH v3 7/10 clk: qcom: clk-cpu-8996: Prepare PLLs on probe

Quoted 14 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Monday, March 19, 2018 18:50
To: Ilia Lin <[email protected]>; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; linux-clk at vger.kernel.org;
sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; ilialin at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: Re: [PATCH v3 07/10] clk: qcom: clk-cpu-8996: Prepare PLLs on probe

Quoted 5 lines

Quoting Ilia Lin (2018-02-14 05:59:49)

Quoted 2 lines

The PLLs must be prepared enabled during the probe to be accessible by the OPPs. Otherwise an OPP may switch to non-enabled clock.

Sounds like an OPP problem.

And again, it could be solved by a platform specific cpufreq driver. Worth it?

Quoted 7 lines
Quoted 7 lines
---
 drivers/clk/qcom/clk-cpu-8996.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
Quoted 12 lines

drivers/clk/qcom/clk-cpu-8996.c line 18

Quoted 10 lines
(quoted diff) +0 -0

b/drivers/clk/qcom/clk-cpu-8996.c index 854f327..b0a3b73 100644

drivers/clk/qcom/clk-cpu-8996.c +1 -1
@@ -15,7 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
-
+#include <linux/clk-provider.h>

Please leave a newline between linux/* and local includes.

Will be changed in the next spin.

Quoted 9 lines
Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c +0 -0
 #include "clk-alpha-pll.h"
 
 #define VCO(a, b, c) { \
@@ -376,6 +376,18 @@ struct clk_hw_clks {
        clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
        clk_alpha_pll_configure(&pwrcl_alt_pll, regmap,
 &altpll_config);
 
Quoted 7 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 383

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
+       /* Enable all PLLs and alt PLLs */
+       clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
+       clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
+       clk_prepare_enable(pwrcl_pll.clkr.hw.clk);
+       clk_prepare_enable(perfcl_pll.clkr.hw.clk);

And this can't be done by the cpufreq-dt driver?

Are you suggesting changing the cpufreq-dt as well?

Quoted 9 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 389

Quoted 7 lines
drivers/clk/qcom/clk-cpu-8996.c +6 -0
+
+       /* Set initial boot frequencies for power/perf PLLs */
+       clk_set_rate(pwrcl_alt_pll.clkr.hw.clk, 652800000);
+       clk_set_rate(perfcl_alt_pll.clkr.hw.clk, 652800000);
+       clk_set_rate(pwrcl_pll.clkr.hw.clk, 652800000);
+       clk_set_rate(perfcl_pll.clkr.hw.clk, 652800000);

We have assigned rates in DT for this.

I assumed that the clock driver can live without the OPP table and any cpufreq driver. Or do you mean adding this as parameters for the kryocc DT node?

Quoted 5 lines
Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +1 -0
+
        ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
        if (ret)
                return ret;
maintainer
#24 lore raw

PATCH v3 7/10 clk: qcom: clk-cpu-8996: Prepare PLLs on probe

Quoting ilialin at codeaurora.org (2018-03-20 06:53:08)

Quoted 39 lines
Quoted 14 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Monday, March 19, 2018 18:50
To: Ilia Lin <[email protected]>; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; linux-clk at vger.kernel.org;
sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; ilialin at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: Re: [PATCH v3 07/10] clk: qcom: clk-cpu-8996: Prepare PLLs on probe

Quoted 5 lines

Quoting Ilia Lin (2018-02-14 05:59:49)

Quoted 2 lines

The PLLs must be prepared enabled during the probe to be accessible by the OPPs. Otherwise an OPP may switch to non-enabled clock.

Sounds like an OPP problem.

And again, it could be solved by a platform specific cpufreq driver. Worth it?

Quoted 9 lines
Quoted 9 lines

#include "clk-alpha-pll.h"

#define VCO(a, b, c) { \

drivers/clk/qcom/clk-cpu-8996.c +0 -0
@@ -376,6 +376,18 @@ struct clk_hw_clks {
        clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
        clk_alpha_pll_configure(&pwrcl_alt_pll, regmap,
 &altpll_config);
 
Quoted 7 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 383

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
+       /* Enable all PLLs and alt PLLs */
+       clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
+       clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
+       clk_prepare_enable(pwrcl_pll.clkr.hw.clk);
+       clk_prepare_enable(perfcl_pll.clkr.hw.clk);

And this can't be done by the cpufreq-dt driver?

Quoted 1 line

Are you suggesting changing the cpufreq-dt as well?

Yes?

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
drivers/clk/qcom/clk-cpu-8996.c +6 -0
+
+       /* Set initial boot frequencies for power/perf PLLs */
+       clk_set_rate(pwrcl_alt_pll.clkr.hw.clk, 652800000);
+       clk_set_rate(perfcl_alt_pll.clkr.hw.clk, 652800000);
+       clk_set_rate(pwrcl_pll.clkr.hw.clk, 652800000);
+       clk_set_rate(perfcl_pll.clkr.hw.clk, 652800000);
Quoted 4 lines
Quoted 1 line

We have assigned rates in DT for this.

I assumed that the clock driver can live without the OPP table and any cpufreq driver. Or do you mean adding this as parameters for the kryocc DT node?

Yes I mean adding assigned rates to the kroycc DT node to setup PLLs to rates you want.

author
#25 lore raw

PATCH v3 8/10 clk: qcom: Add ACD path to CPU clock driver for msm8996

In reply to Ilia Lin

The PMUX for each duplex allows for selection of ACD clock source. The DVM (Dynamic Variation Monitor) will flag an error
when a voltage droop event is detected. This flagged error enables ACD to provide a div-by-2 clock, sourced from the primary PLL. The duplex will be provided the divided clock
until a pre-programmed delay has expired.

This change configures ACD during the probe and switches the PMUXes to the ACD clock source.

---
 drivers/clk/qcom/clk-cpu-8996.c | 110 ++++++++++++++++++++++++++++++++++------
 1 file changed, 95 insertions(+), 15 deletions(-)
drivers/clk/qcom/clk-cpu-8996.c +95 -15
index b0a3b73..1552791 100644
@@ -17,6 +17,7 @@
 #include <linux/regmap.h>
 #include <linux/clk-provider.h>
 #include "clk-alpha-pll.h"
+#include <soc/qcom/kryo-l2-accessors.h>
 
 #define VCO(a, b, c) { \
 	.val = a,\
@@ -29,6 +30,27 @@
 #define ACD_INDEX		2
 #define ALT_INDEX		3
 #define DIV_2_THRESHOLD		600000000
+#define PWRCL_REG_OFFSET 0x0
+#define PERFCL_REG_OFFSET 0x80000
+#define MUX_OFFSET	0x40
+#define ALT_PLL_OFFSET	0x100
+#define SSSCTL_OFFSET 0x160
+/*
+APCy_QLL_SSSCTL value:
+SACDRCLEN=1
+SSWEN=1
+SSTRTEN=1
+SSTPAPMSWEN=1
+*/
+#define SSSCTL_VAL 0xF
+
+enum {
+	APC_BASE,
+	EFUSE_BASE,
+	NUM_BASES
+};
+
+static void __iomem *vbases[NUM_BASES];
 
 static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
        [PLL_OFF_L_VAL] = 0x04,
@@ -67,7 +89,7 @@
 };
 
 static struct clk_alpha_pll perfcl_pll = {
-	.offset = 0x80000,
+	.offset = PERFCL_REG_OFFSET,
 	.regs = prim_pll_regs,
 	.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
 	.clkr.hw.init = &(struct clk_init_data){
@@ -79,7 +101,7 @@
 };
 
 static struct clk_alpha_pll pwrcl_pll = {
-	.offset = 0x0,
+	.offset = PWRCL_REG_OFFSET,
 	.regs = prim_pll_regs,
 	.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
 	.clkr.hw.init = &(struct clk_init_data){
@@ -109,7 +131,7 @@
 };
 
 static struct clk_alpha_pll perfcl_alt_pll = {
-	.offset = 0x80100,
+	.offset = PERFCL_REG_OFFSET + ALT_PLL_OFFSET,
 	.regs = alt_pll_regs,
 	.vco_table = alt_pll_vco_modes,
 	.num_vco = ARRAY_SIZE(alt_pll_vco_modes),
@@ -123,7 +145,7 @@
 };
 
 static struct clk_alpha_pll pwrcl_alt_pll = {
-	.offset = 0x100,
+	.offset = PWRCL_REG_OFFSET + ALT_PLL_OFFSET,
 	.regs = alt_pll_regs,
 	.vco_table = alt_pll_vco_modes,
 	.num_vco = ARRAY_SIZE(alt_pll_vco_modes),
@@ -136,6 +158,8 @@
 	},
 };
 
+static void qcom_cpu_clk_msm8996_acd_init(void);
+
 /* Mux'es */
 
 struct clk_cpu_8996_mux {
@@ -218,6 +242,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 	switch (event) {
 	case PRE_RATE_CHANGE:
 		ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
+		qcom_cpu_clk_msm8996_acd_init();
 		break;
 	case POST_RATE_CHANGE:
 		if (cnd->new_rate < DIV_2_THRESHOLD)
@@ -225,7 +250,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 							  DIV_2_INDEX);
 		else
 			ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
-							  PLL_INDEX);
+							  ACD_INDEX);
 		break;
 	default:
 		ret = 0;
@@ -242,7 +267,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 };
 
 static struct clk_cpu_8996_mux pwrcl_smux = {
-	.reg = 0x40,
+	.reg = PWRCL_REG_OFFSET + MUX_OFFSET,
 	.shift = 2,
 	.width = 2,
 	.clkr.hw.init = &(struct clk_init_data) {
@@ -258,7 +283,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 };
 
 static struct clk_cpu_8996_mux perfcl_smux = {
-	.reg = 0x80040,
+	.reg = PERFCL_REG_OFFSET + MUX_OFFSET,
 	.shift = 2,
 	.width = 2,
 	.clkr.hw.init = &(struct clk_init_data) {
@@ -274,7 +299,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 };
 
 static struct clk_cpu_8996_mux pwrcl_pmux = {
-	.reg = 0x40,
+	.reg = PWRCL_REG_OFFSET + MUX_OFFSET,
 	.shift = 0,
 	.width = 2,
 	.pll = &pwrcl_pll.clkr.hw,
@@ -295,7 +320,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
 };
 
 static struct clk_cpu_8996_mux perfcl_pmux = {
-	.reg = 0x80040,
+	.reg = PERFCL_REG_OFFSET + MUX_OFFSET,
 	.shift = 0,
 	.width = 2,
 	.pll = &perfcl_pll.clkr.hw,
@@ -399,10 +424,64 @@ struct clk_hw_clks {
 	return ret;
 }
 
+#define CPU_AFINITY_MASK 0xFFF
+#define PWRCL_CPU_REG_MASK 0x3
+#define PERFCL_CPU_REG_MASK 0x103
+
+/* ACD static settings (HMSS HPG 7.2.2) */
+#define L2ACDCR_REG 0x580ULL
+#define L2ACDTD_REG 0x581ULL
+#define L2ACDDVMRC_REG 0x584ULL
+#define L2ACDSSCR_REG 0x589ULL
+#define ACDTD_VAL 0x00006A11
+#define ACDCR_VAL 0x002C5FFD
+#define ACDSSCR_VAL 0x00000601
+#define ACDDVMRC_VAL 0x000E0F0F
+
+static DEFINE_SPINLOCK(acd_lock);
+
+static void qcom_cpu_clk_msm8996_acd_init(void)
+{
+	u64 hwid;
+	unsigned long flags;
+
+	spin_lock_irqsave(&acd_lock, flags);
+
+	hwid = read_cpuid_mpidr() & CPU_AFINITY_MASK;
+
+	/* Program ACD Tunable-Length Delay (TLD) */
+	set_l2_indirect_reg(L2ACDTD_REG, ACDTD_VAL);
+	/* Initial ACD for *this* cluster */
+	set_l2_indirect_reg(L2ACDDVMRC_REG, ACDDVMRC_VAL);
+	/* Program ACD soft start control bits. */
+	set_l2_indirect_reg(L2ACDSSCR_REG, ACDSSCR_VAL);
+
+	if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) {
+		/* Enable Soft Stop/Start */
+		if (vbases[APC_BASE])
+			writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+					PWRCL_REG_OFFSET + SSSCTL_OFFSET);
+		/* Ensure SSSCTL config goes through before enabling ACD. */
+		mb();
+		/* Program ACD control bits */
+		set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+	}
+	if (PERFCL_CPU_REG_MASK == (hwid | PERFCL_CPU_REG_MASK)) { //else {
+		/* Program ACD control bits */
+		set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+		/* Enable Soft Stop/Start */
+		if (vbases[APC_BASE])
+			writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+					PERFCL_REG_OFFSET + SSSCTL_OFFSET);
+		/* Ensure SSSCTL config goes through before enabling ACD. */
+		mb();
+	}
+
+	spin_unlock_irqrestore(&acd_lock, flags);
+}
 static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
 {
 	int ret;
-	void __iomem *base;
 	struct resource *res;
 	struct regmap *regmap_cpu;
 	struct clk_hw_clks *hws;
@@ -415,17 +494,17 @@ static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
 	if (!data)
 		return -ENOMEM;
 
-	hws = devm_kzalloc(dev, sizeof(*hws) + 2 * sizeof(struct clk_hw *),
+	hws = devm_kzalloc(dev, sizeof(*hws) + 4 * sizeof(struct clk_hw *),
 			   GFP_KERNEL);
 	if (!hws)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(base))
-		return PTR_ERR(base);
+	vbases[APC_BASE] = devm_ioremap_resource(dev, res);
+	if (IS_ERR(vbases[APC_BASE]))
+		return PTR_ERR(vbases[APC_BASE]);
 
-	regmap_cpu = devm_regmap_init_mmio(dev, base,
+	regmap_cpu = devm_regmap_init_mmio(dev, vbases[APC_BASE],
 					   &cpu_msm8996_regmap_config);
 	if (IS_ERR(regmap_cpu))
 		return PTR_ERR(regmap_cpu);
@@ -433,6 +512,7 @@ static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
 	ret = qcom_cpu_clk_msm8996_register_clks(dev, hws, regmap_cpu);
 	if (ret)
 		return ret;
+	qcom_cpu_clk_msm8996_acd_init();
 
 	data->hws[0] = &pwrcl_pmux.clkr.hw;
 	data->hws[1] = &perfcl_pmux.clkr.hw;
Signature · 1 line
1.9.1
maintainer
#26 lore raw

PATCH v3 8/10 clk: qcom: Add ACD path to CPU clock driver for msm8996

Quoting Ilia Lin (2018-02-14 05:59:50)

drivers/clk/qcom/clk-cpu-8996.c line 20

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c +1 -0
index b0a3b73..1552791 100644
@@ -17,6 +17,7 @@
 #include <linux/regmap.h>
 #include <linux/clk-provider.h>
 #include "clk-alpha-pll.h"
+#include <soc/qcom/kryo-l2-accessors.h>

Put this above local includes please.

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c +2 -0
 #define VCO(a, b, c) { \
        .val = a,\
@@ -29,6 +30,27 @@
 #define ACD_INDEX              2
 #define ALT_INDEX              3
 #define DIV_2_THRESHOLD                600000000
+#define PWRCL_REG_OFFSET 0x0
+#define PERFCL_REG_OFFSET 0x80000

drivers/clk/qcom/clk-cpu-8996.c line 44

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c +10 -0
+#define MUX_OFFSET     0x40
+#define ALT_PLL_OFFSET 0x100
+#define SSSCTL_OFFSET 0x160
+/*
+APCy_QLL_SSSCTL value:
+SACDRCLEN=1
+SSWEN=1
+SSTRTEN=1
+SSTPAPMSWEN=1
+*/

Bad comment style and I have no idea what it means.

drivers/clk/qcom/clk-cpu-8996.c line 49

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
+#define SSSCTL_VAL 0xF
+
+enum {
+       APC_BASE,
+       EFUSE_BASE,

Is this used? efuse should go through nvmem APIs.

drivers/clk/qcom/clk-cpu-8996.c line 53

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c +4 -0
+       NUM_BASES
+};
+
+static void __iomem *vbases[NUM_BASES];

Please just pass this to the function that uses it and drop EFUSE_BASE.

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c +3 -0
 static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
        [PLL_OFF_L_VAL] = 0x04,
@@ -399,10 +424,64 @@ struct clk_hw_clks {
        return ret;
 }
 
+#define CPU_AFINITY_MASK 0xFFF
+#define PWRCL_CPU_REG_MASK 0x3
+#define PERFCL_CPU_REG_MASK 0x103

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 439

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c +10 -0
+
+/* ACD static settings (HMSS HPG 7.2.2) */
+#define L2ACDCR_REG 0x580ULL
+#define L2ACDTD_REG 0x581ULL
+#define L2ACDDVMRC_REG 0x584ULL
+#define L2ACDSSCR_REG 0x589ULL
+#define ACDTD_VAL 0x00006A11
+#define ACDCR_VAL 0x002C5FFD
+#define ACDSSCR_VAL 0x00000601
+#define ACDDVMRC_VAL 0x000E0F0F

Please don't have #defines for random register settings. It just obfuscates what's going on at the place where the define is used.

Quoted 8 lines
drivers/clk/qcom/clk-cpu-8996.c +8 -0
+
+static DEFINE_SPINLOCK(acd_lock);
+
+static void qcom_cpu_clk_msm8996_acd_init(void)
+{
+       u64 hwid;
+       unsigned long flags;
+

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 457

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c +10 -0
+       spin_lock_irqsave(&acd_lock, flags);
+
+       hwid = read_cpuid_mpidr() & CPU_AFINITY_MASK;
+
+       /* Program ACD Tunable-Length Delay (TLD) */
+       set_l2_indirect_reg(L2ACDTD_REG, ACDTD_VAL);
+       /* Initial ACD for *this* cluster */
+       set_l2_indirect_reg(L2ACDDVMRC_REG, ACDDVMRC_VAL);
+       /* Program ACD soft start control bits. */
+       set_l2_indirect_reg(L2ACDSSCR_REG, ACDSSCR_VAL);

Please remove all useless comments, the code is obviously touching registers.

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 460

Quoted 3 lines
drivers/clk/qcom/clk-cpu-8996.c +3 -0
+
+       if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) {
+               /* Enable Soft Stop/Start */

Sigh.

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 461

Quoted 1 line
drivers/clk/qcom/clk-cpu-8996.c +1 -0
+               if (vbases[APC_BASE])

When is this false?

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 465

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c +4 -0
+                       writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+                                       PWRCL_REG_OFFSET + SSSCTL_OFFSET);
+               /* Ensure SSSCTL config goes through before enabling ACD. */
+               mb();

Use writel instead.

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 469

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c +4 -0
+               /* Program ACD control bits */
+               set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+       }
+       if (PERFCL_CPU_REG_MASK == (hwid | PERFCL_CPU_REG_MASK)) { //else {

What is that '// else {' stuff?

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 477

Quoted 8 lines
drivers/clk/qcom/clk-cpu-8996.c +8 -0
+               /* Program ACD control bits */
+               set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+               /* Enable Soft Stop/Start */
+               if (vbases[APC_BASE])
+                       writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+                                       PERFCL_REG_OFFSET + SSSCTL_OFFSET);
+               /* Ensure SSSCTL config goes through before enabling ACD. */
+               mb();

Again, use writel.

Quoted 24 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -4
+       }
+
+       spin_unlock_irqrestore(&acd_lock, flags);
+}
 static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
 {
        int ret;
-       void __iomem *base;
        struct resource *res;
        struct regmap *regmap_cpu;
        struct clk_hw_clks *hws;
@@ -415,17 +494,17 @@ static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
        if (!data)
                return -ENOMEM;
 
-       hws = devm_kzalloc(dev, sizeof(*hws) + 2 * sizeof(struct clk_hw *),
+       hws = devm_kzalloc(dev, sizeof(*hws) + 4 * sizeof(struct clk_hw *),
                           GFP_KERNEL);
        if (!hws)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(base))

drivers/clk/qcom/clk-cpu-8996.c static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev) · line 510

Quoted 10 lines
drivers/clk/qcom/clk-cpu-8996.c +4 -2
-               return PTR_ERR(base);
+       vbases[APC_BASE] = devm_ioremap_resource(dev, res);
+       if (IS_ERR(vbases[APC_BASE]))
+               return PTR_ERR(vbases[APC_BASE]);
 
-       regmap_cpu = devm_regmap_init_mmio(dev, base,
+       regmap_cpu = devm_regmap_init_mmio(dev, vbases[APC_BASE],
                                           &cpu_msm8996_regmap_config);
        if (IS_ERR(regmap_cpu))
                return PTR_ERR(regmap_cpu);

Cool, none of this diff is needed.

drivers/clk/qcom/clk-cpu-8996.c static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev) · line 515

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +1 -0
@@ -433,6 +512,7 @@ static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
        ret = qcom_cpu_clk_msm8996_register_clks(dev, hws, regmap_cpu);
        if (ret)
                return ret;
+       qcom_cpu_clk_msm8996_acd_init();

Pass base here.

Quoted 3 lines
drivers/clk/qcom/clk-cpu-8996.c +0 -0
        data->hws[0] = &pwrcl_pmux.clkr.hw;
        data->hws[1] = &perfcl_pmux.clkr.hw;
#27 lore raw

PATCH v3 8/10 clk: qcom: Add ACD path to CPU clock driver for msm8996

On 19/03/18 16:57, Stephen Boyd wrote:
[...]

Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 460

Quoted 3 lines
drivers/clk/qcom/clk-cpu-8996.c +3 -0
+
+       if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) {
+               /* Enable Soft Stop/Start */

Sigh.

Quoted 1 line

+ if (vbases[APC_BASE])

Quoted 8 lines

When is this false?

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 465

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c +4 -0
+                       writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+                                       PWRCL_REG_OFFSET + SSSCTL_OFFSET);
+               /* Ensure SSSCTL config goes through before enabling ACD. */
+               mb();

Use writel instead.

Note that writel() only gives an implicit wmb() *before* the store to ensure ordering against any previous writes. If this code really needs to ensure that the given write has definitely completed before any other accesses happen, then it still needs an explicit barrier *after* the write*(), unless perhaps the next access is always guaranteed to be a non-relaxed write (thus implicitly providing a suitable DSB).

Robin.

maintainer
#28 lore raw

PATCH v3 8/10 clk: qcom: Add ACD path to CPU clock driver for msm8996

Quoting Robin Murphy (2018-03-19 11:16:15)

Quoted 9 lines · Stephen Boyd

[...]

Quoted 7 lines
Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
+
 
+                       writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+                                       PWRCL_REG_OFFSET + SSSCTL_OFFSET);
+               /* Ensure SSSCTL config goes through before enabling ACD. */
+               mb();
Quoted 9 lines
Quoted 1 line

Use writel instead.

Note that writel() only gives an implicit wmb() *before* the store to ensure ordering against any previous writes. If this code really needs to ensure that the given write has definitely completed before any other accesses happen, then it still needs an explicit barrier *after* the write*(), unless perhaps the next access is always guaranteed to be a non-relaxed write (thus implicitly providing a suitable DSB).

Ah right. So this should be a wmb() too? I suspect it's to order with the write to the l2 indirect registers, but reading that register before the MMIO write is not a problem. The comment above the l2 accessors could be slightly more specific here and it would help immensely.

#29 lore raw

PATCH v3 8/10 clk: qcom: Add ACD path to CPU clock driver for msm8996

Quoted 20 lines · Stephen Boyd

Quoting Robin Murphy (2018-03-19 11:16:15)

Quoted 9 lines · Stephen Boyd

[...]

Quoted 7 lines
Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
+
 
+                       writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+                                       PWRCL_REG_OFFSET + SSSCTL_OFFSET);
+               /* Ensure SSSCTL config goes through before enabling ACD. */
+               mb();
Quoted 9 lines
Quoted 1 line

Use writel instead.

Note that writel() only gives an implicit wmb() *before* the store to ensure ordering against any previous writes. If this code really needs to ensure that the given write has definitely completed before any other accesses happen, then it still needs an explicit barrier *after* the write*(), unless perhaps the next access is always guaranteed to be a non-relaxed write (thus implicitly providing a suitable DSB).

Quoted 4 lines

Ah right. So this should be a wmb() too? I suspect it's to order with the write to the l2 indirect registers, but reading that register before the MMIO write is not a problem. The comment above the l2 accessors could be slightly more specific here and it would help immensely.

It depends a bit on what exactly the hardware requires. If it's merely that write(s) to register A (and perhaps others) arrive before any write to register B, then the sensible thing to do would be to just make the write to B non-relaxed, i.e.:

	writel_relaxed(x, base + A);
	...
	writel(y, base + B);

That still only guarantees that the previous write(s) have been pushed all the way to the endpoint before the write to B is issued, though - for many devices that's sufficient, but in some cases the only way to be totally sure that the write has both been received *and* taken effect is by reading back some suitable indicator before proceeding.

If we only care about making sure writes are pushed out, rather than synchronising more complicated memory accesses between multiple agents, then a full mb() is probably overkill (as ordering against outstanding loads too only adds more overhead in the interconnect), and wmb() (ideally implicit in a subsequent writel() as above) should be enough.

Robin.

#30 lore raw

PATCH v3 8/10 clk: qcom: Add ACD path to CPU clock driver for msm8996

In reply to Stephen Boyd
Quoted 16 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Monday, March 19, 2018 18:57
To: Ilia Lin <[email protected]>; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; linux-clk at vger.kernel.org;
sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; ilialin at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: Re: [PATCH v3 08/10] clk: qcom: Add ACD path to CPU clock driver for msm8996

Quoting Ilia Lin (2018-02-14 05:59:50)

Quoted 11 lines

drivers/clk/qcom/clk-cpu-8996.c line 20

Quoted 9 lines
(quoted diff) +0 -0

b/drivers/clk/qcom/clk-cpu-8996.c index b0a3b73..1552791 100644

drivers/clk/qcom/clk-cpu-8996.c +1 -0
@@ -17,6 +17,7 @@
 #include <linux/regmap.h>
 #include <linux/clk-provider.h>
 #include "clk-alpha-pll.h"
+#include <soc/qcom/kryo-l2-accessors.h>

Put this above local includes please.

Will be changed in the next spin.

Quoted 14 lines
Quoted 14 lines
drivers/clk/qcom/clk-cpu-8996.c +6 -0
 #define VCO(a, b, c) { \
        .val = a,\
@@ -29,6 +30,27 @@
 #define ACD_INDEX              2
 #define ALT_INDEX              3
 #define DIV_2_THRESHOLD                600000000
+#define PWRCL_REG_OFFSET 0x0
+#define PERFCL_REG_OFFSET 0x80000
+#define MUX_OFFSET     0x40
+#define ALT_PLL_OFFSET 0x100
+#define SSSCTL_OFFSET 0x160
+/*
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 44

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c +6 -0
+APCy_QLL_SSSCTL value:
+SACDRCLEN=1
+SSWEN=1
+SSTRTEN=1
+SSTPAPMSWEN=1
+*/

Bad comment style and I have no idea what it means.

Will be changed in the next spin.

Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c line 49

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
+#define SSSCTL_VAL 0xF
+
+enum {
+       APC_BASE,
+       EFUSE_BASE,

Is this used? efuse should go through nvmem APIs.

Will be removed in the next spin.

Quoted 7 lines

drivers/clk/qcom/clk-cpu-8996.c line 53

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +4 -0
+       NUM_BASES
+};
+
+static void __iomem *vbases[NUM_BASES];

Please just pass this to the function that uses it and drop EFUSE_BASE.

Will be changed in the next spin.

Quoted 15 lines
Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +0 -0
 static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
        [PLL_OFF_L_VAL] = 0x04,

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 432

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c +6 -0
@@ -399,10 +424,64 @@ struct clk_hw_clks {
        return ret;
 }
 
+#define CPU_AFINITY_MASK 0xFFF
+#define PWRCL_CPU_REG_MASK 0x3
+#define PERFCL_CPU_REG_MASK 0x103
+
+/* ACD static settings (HMSS HPG 7.2.2) */ #define L2ACDCR_REG
+0x580ULL #define L2ACDTD_REG 0x581ULL #define L2ACDDVMRC_REG

0x584ULL

Quoted 7 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 433

Quoted 1 line
drivers/clk/qcom/clk-cpu-8996.c +1 -0
+#define L2ACDSSCR_REG 0x589ULL #define ACDTD_VAL 0x00006A11

#define

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 435

Quoted 2 lines
drivers/clk/qcom/clk-cpu-8996.c +2 -0
+ACDCR_VAL 0x002C5FFD #define ACDSSCR_VAL 0x00000601 #define
+ACDDVMRC_VAL 0x000E0F0F

Please don't have #defines for random register settings. It just obfuscates what's going on at the place where the define is used.

So should I just use the values directly?

Quoted 14 lines
Quoted 14 lines
drivers/clk/qcom/clk-cpu-8996.c +13 -0
+
+static DEFINE_SPINLOCK(acd_lock);
+
+static void qcom_cpu_clk_msm8996_acd_init(void)
+{
+       u64 hwid;
+       unsigned long flags;
+
+       spin_lock_irqsave(&acd_lock, flags);
+
+       hwid = read_cpuid_mpidr() & CPU_AFINITY_MASK;
+
+       /* Program ACD Tunable-Length Delay (TLD) */
Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 457

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
+       set_l2_indirect_reg(L2ACDTD_REG, ACDTD_VAL);
+       /* Initial ACD for *this* cluster */
+       set_l2_indirect_reg(L2ACDDVMRC_REG, ACDDVMRC_VAL);
+       /* Program ACD soft start control bits. */
+       set_l2_indirect_reg(L2ACDSSCR_REG, ACDSSCR_VAL);

Please remove all useless comments, the code is obviously touching registers.

Will be changed in the next spin.

Quoted 10 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 460

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c +3 -0
+
+       if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) {
+               /* Enable Soft Stop/Start */

Sigh.

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 457

Quoted 1 line
drivers/clk/qcom/clk-cpu-8996.c +1 -0
+               if (vbases[APC_BASE])

When is this false?

It is checked in the probe. You are right, I'll remove this check and pass the base as argument.

Quoted 7 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 465

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +4 -0
+                       writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+                                       PWRCL_REG_OFFSET + SSSCTL_OFFSET);
+               /* Ensure SSSCTL config goes through before enabling ACD. */
+               mb();

Use writel instead.

OK

Quoted 8 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks {

Quoted 6 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -0
+               /* Program ACD control bits */
+               set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+       }
+       if (PERFCL_CPU_REG_MASK == (hwid | PERFCL_CPU_REG_MASK)) {
+ //else {

What is that '// else {' stuff?

Missed leftover. Will be changed in the next spin.

Quoted 11 lines

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 477

Quoted 9 lines
drivers/clk/qcom/clk-cpu-8996.c +8 -0
+               /* Program ACD control bits */
+               set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+               /* Enable Soft Stop/Start */
+               if (vbases[APC_BASE])
+                       writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+                                       PERFCL_REG_OFFSET + SSSCTL_OFFSET);
+               /* Ensure SSSCTL config goes through before enabling ACD. */
+               mb();

Again, use writel.

OK

Quoted 31 lines

drivers/clk/qcom/clk-cpu-8996.c static int

Quoted 12 lines
drivers/clk/qcom/clk-cpu-8996.c +3 -1
+       }
+
+       spin_unlock_irqrestore(&acd_lock, flags); }
 static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device
 *pdev)  {
        int ret;
-       void __iomem *base;
        struct resource *res;
        struct regmap *regmap_cpu;
        struct clk_hw_clks *hws;
@@ -415,17 +494,17 @@ static int

qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)

Quoted 18 lines
drivers/clk/qcom/clk-cpu-8996.c +5 -4
        if (!data)
                return -ENOMEM;
 
-       hws = devm_kzalloc(dev, sizeof(*hws) + 2 * sizeof(struct clk_hw *),
+       hws = devm_kzalloc(dev, sizeof(*hws) + 4 * sizeof(struct
+ clk_hw *),
                           GFP_KERNEL);
        if (!hws)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
+       vbases[APC_BASE] = devm_ioremap_resource(dev, res);
+       if (IS_ERR(vbases[APC_BASE]))
+               return PTR_ERR(vbases[APC_BASE]);
 
Quoted 7 lines

drivers/clk/qcom/clk-cpu-8996.c static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev) · line 510

Quoted 5 lines
drivers/clk/qcom/clk-cpu-8996.c +1 -1
-       regmap_cpu = devm_regmap_init_mmio(dev, base,
+       regmap_cpu = devm_regmap_init_mmio(dev, vbases[APC_BASE],
                                           &cpu_msm8996_regmap_config);
        if (IS_ERR(regmap_cpu))
                return PTR_ERR(regmap_cpu);

Cool, none of this diff is needed.

Since the effuse code will not be implemented in the clock driver, you are right. Will be changed in the next spin.

Quoted 9 lines

drivers/clk/qcom/clk-cpu-8996.c static int

Quoted 2 lines
drivers/clk/qcom/clk-cpu-8996.c +0 -0
@@ -433,6 +512,7 @@ static int

qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)

drivers/clk/qcom/clk-cpu-8996.c static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev) · line 515

Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c +1 -0
        ret = qcom_cpu_clk_msm8996_register_clks(dev, hws, regmap_cpu);
        if (ret)
                return ret;
+       qcom_cpu_clk_msm8996_acd_init();

Pass base here.

Sure.

Quoted 4 lines
Quoted 4 lines
drivers/clk/qcom/clk-cpu-8996.c +0 -0
        data->hws[0] = &pwrcl_pmux.clkr.hw;
        data->hws[1] = &perfcl_pmux.clkr.hw;
maintainer
#31 lore raw

PATCH v3 8/10 clk: qcom: Add ACD path to CPU clock driver for msm8996

Quoting ilialin at codeaurora.org (2018-03-20 07:04:05)

Quoted 18 lines
Quoted 18 lines

From: Stephen Boyd <[email protected]>
Quoting Ilia Lin (2018-02-14 05:59:50)

drivers/clk/qcom/clk-cpu-8996.c struct clk_hw_clks { · line 432

Quoted 13 lines
 static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
        [PLL_OFF_L_VAL] = 0x04,
drivers/clk/qcom/clk-cpu-8996.c +6 -0
@@ -399,10 +424,64 @@ struct clk_hw_clks {
        return ret;
 }
 
+#define CPU_AFINITY_MASK 0xFFF
+#define PWRCL_CPU_REG_MASK 0x3
+#define PERFCL_CPU_REG_MASK 0x103
+
+/* ACD static settings (HMSS HPG 7.2.2) */ #define L2ACDCR_REG
+0x580ULL #define L2ACDTD_REG 0x581ULL #define L2ACDDVMRC_REG

0x584ULL

Quoted 1 line
(quoted diff) +1 -0
+#define L2ACDSSCR_REG 0x589ULL #define ACDTD_VAL 0x00006A11
Quoted 8 lines
Quoted 6 lines

#define

Review struct clk_hw_clks { · line 435

Quoted 2 lines
(quoted diff) +2 -0
+ACDCR_VAL 0x002C5FFD #define ACDSSCR_VAL 0x00000601 #define
+ACDDVMRC_VAL 0x000E0F0F

Please don't have #defines for random register settings. It just obfuscates what's going on at the place where the define is used.

So should I just use the values directly?

Yes.

author
#32 lore raw

PATCH v3 9/10 DT: QCOM: Add cpufreq-dt to msm8996

In reply to Ilia Lin

Add device tree frequency table for the MSM8996 to be used by the upstream cpufreq-dt driver with the clk-cpu-8996 driver as infrastructure.

---
 arch/arm64/boot/dts/qcom/apq8096-db820c.dts  |   4 +-
 arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi |   2 +-
 arch/arm64/boot/dts/qcom/msm8996.dtsi        | 188 ++++++++++++++++++++++++++-
 drivers/cpufreq/cpufreq-dt-platdev.c         |   3 +
 4 files changed, 192 insertions(+), 5 deletions(-)
arch/arm64/boot/dts/qcom/apq8096-db820c.dts +2 -2
index 230e9c8..632cb42 100644
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016,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
@@ -17,5 +17,5 @@
 
 / {
 	model = "Qualcomm Technologies, Inc. DB820c";
-	compatible = "arrow,apq8096-db820c", "qcom,apq8096-sbc";
+	compatible = "arrow,apq8096-db820c", "qcom,apq8096-sbc", "qcom,apq8096";
 };
arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi +1 -1
index 492a011..930f68b 100644
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016,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
arch/arm64/boot/dts/qcom/msm8996.dtsi +186 -2

227 lines not on this page · raw message

drivers/cpufreq/cpufreq-dt-platdev.c +3 -0
index 3b585e4..b6cd0ae 100644
@@ -95,6 +95,9 @@
 	{ .compatible = "xlnx,zynq-7000", },
 	{ .compatible = "xlnx,zynqmp", },
 
+	{ .compatible = "qcom,msm8996", },
+	{ .compatible = "qcom,apq8096", },
+
 	{ }
 };
 
Signature · 1 line
1.9.1
maintainer
#33 lore raw

PATCH v3 9/10 DT: QCOM: Add cpufreq-dt to msm8996

Quoting Ilia Lin (2018-02-14 05:59:51)

arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi line 5

Quoted 11 lines
arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi +1 -1
index 492a011..930f68b 100644
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016,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

Why?

Quoted 11 lines
arch/arm64/boot/dts/qcom/msm8996.dtsi +3 -0
index 4b2afcc..0359197 100644
@@ -144,6 +152,182 @@
                };
        };
 
+       cluster0_opp: opp_table0 {
+               compatible = "operating-points-v2";
+               opp-shared;

arch/arm64/boot/dts/qcom/msm8996.dtsi line 167

Quoted 10 lines
arch/arm64/boot/dts/qcom/msm8996.dtsi +10 -0
+
+               opp at 307200000 {
+                       opp-hz = /bits/ 64 <  307200000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 422400000 {
+                       opp-hz = /bits/ 64 <  422400000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 480000000 {

It looks like opp-480000000 now instead of opp@<freq>.

Quoted 52 lines
arch/arm64/boot/dts/qcom/msm8996.dtsi +52 -0
+                       opp-hz = /bits/ 64 <  480000000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 556800000 {
+                       opp-hz = /bits/ 64 <  556800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 652800000 {
+                       opp-hz = /bits/ 64 <  652800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 729600000 {
+                       opp-hz = /bits/ 64 <  729600000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 844800000 {
+                       opp-hz = /bits/ 64 <  844800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 960000000 {
+                       opp-hz = /bits/ 64 <  960000000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1036800000 {
+                       opp-hz = /bits/ 64 < 1036800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1113600000 {
+                       opp-hz = /bits/ 64 < 1113600000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1190400000 {
+                       opp-hz = /bits/ 64 < 1190400000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1228800000 {
+                       opp-hz = /bits/ 64 < 1228800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1324800000 {
+                       opp-hz = /bits/ 64 < 1324800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1401600000 {
+                       opp-hz = /bits/ 64 < 1401600000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1478400000 {
+                       opp-hz = /bits/ 64 < 1478400000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1593600000 {

[...]

arch/arm64/boot/dts/qcom/msm8996.dtsi line 590

Quoted 11 lines
arch/arm64/boot/dts/qcom/msm8996.dtsi +3 -1
+
+       };
        thermal-zones {
                cpu-thermal0 {
                        polling-delay-passive = <250>;
@@ -403,7 +587,7 @@
                };
 
                kryocc: clock-controller at 6400000 {
-                       compatible = "qcom,apcc-msm8996";
+                       compatible = "qcom-msm8996-apcc";

Bad change?

Quoted 8 lines
arch/arm64/boot/dts/qcom/msm8996.dtsi +0 -0
                        reg = <0x6400000 0x90000>;
                        #clock-cells = <1>;
                };
drivers/cpufreq/cpufreq-dt-platdev.c +0 -0
index 3b585e4..b6cd0ae 100644

drivers/cpufreq/cpufreq-dt-platdev.c line 100

Quoted 6 lines
drivers/cpufreq/cpufreq-dt-platdev.c +3 -0
@@ -95,6 +95,9 @@
        { .compatible = "xlnx,zynq-7000", },
        { .compatible = "xlnx,zynqmp", },
 
+       { .compatible = "qcom,msm8996", },
+       { .compatible = "qcom,apq8096", },
+

Why can't we base it on the kryocc node being present? Or even populate the cpufreq-dt from the kryocc driver?

#34 lore raw

PATCH v3 9/10 DT: QCOM: Add cpufreq-dt to msm8996

Quoted 15 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Monday, March 19, 2018 18:49
To: Ilia Lin <[email protected]>; linux-arm-kernel at lists.infradead.org; linux-arm-msm at vger.kernel.org; linux-clk at vger.kernel.org;
sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; ilialin at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: Re: [PATCH v3 09/10] DT: QCOM: Add cpufreq-dt to msm8996

Quoting Ilia Lin (2018-02-14 05:59:51)

Quoted 14 lines

arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi line 5

Quoted 12 lines
arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi +1 -1
index 492a011..930f68b 100644
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016,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

Why?

The file was changed again in 2018. I'm reflecting this in the file dates.

Quoted 10 lines
Quoted 10 lines
arch/arm64/boot/dts/qcom/msm8996.dtsi +0 -0
index 4b2afcc..0359197 100644
@@ -144,6 +152,182 @@
                };
        };
 
Quoted 15 lines

arch/arm64/boot/dts/qcom/msm8996.dtsi line 167

Quoted 13 lines
arch/arm64/boot/dts/qcom/msm8996.dtsi +13 -0
+       cluster0_opp: opp_table0 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp at 307200000 {
+                       opp-hz = /bits/ 64 <  307200000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 422400000 {
+                       opp-hz = /bits/ 64 <  422400000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 480000000 {

It looks like opp-480000000 now instead of opp@<freq>.

Will be changed in the next spin.

Quoted 62 lines
Quoted 53 lines
arch/arm64/boot/dts/qcom/msm8996.dtsi +52 -0
+                       opp-hz = /bits/ 64 <  480000000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 556800000 {
+                       opp-hz = /bits/ 64 <  556800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 652800000 {
+                       opp-hz = /bits/ 64 <  652800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 729600000 {
+                       opp-hz = /bits/ 64 <  729600000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 844800000 {
+                       opp-hz = /bits/ 64 <  844800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 960000000 {
+                       opp-hz = /bits/ 64 <  960000000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1036800000 {
+                       opp-hz = /bits/ 64 < 1036800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1113600000 {
+                       opp-hz = /bits/ 64 < 1113600000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1190400000 {
+                       opp-hz = /bits/ 64 < 1190400000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1228800000 {
+                       opp-hz = /bits/ 64 < 1228800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1324800000 {
+                       opp-hz = /bits/ 64 < 1324800000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1401600000 {
+                       opp-hz = /bits/ 64 < 1401600000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1478400000 {
+                       opp-hz = /bits/ 64 < 1478400000 >;
+                       clock-latency-ns = <200000>;
+               };
+               opp at 1593600000 {

[...]

Quoted 8 lines
arch/arm64/boot/dts/qcom/msm8996.dtsi +3 -0
+
+       };
        thermal-zones {
                cpu-thermal0 {
                        polling-delay-passive = <250>; @@ -403,7
+587,7 @@
                };
Quoted 5 lines

arch/arm64/boot/dts/qcom/msm8996.dtsi line 590

Quoted 3 lines
                kryocc: clock-controller at 6400000 {
arch/arm64/boot/dts/qcom/msm8996.dtsi +1 -1
-                       compatible = "qcom,apcc-msm8996";
+                       compatible = "qcom-msm8996-apcc";

Bad change?

This was required by Rob Herring.

Quoted 13 lines
Quoted 13 lines
                        reg = <0x6400000 0x90000>;
                        #clock-cells = <1>;
                };
drivers/cpufreq/cpufreq-dt-platdev.c +0 -0
index 3b585e4..b6cd0ae 100644
@@ -95,6 +95,9 @@
        { .compatible = "xlnx,zynq-7000", },
        { .compatible = "xlnx,zynqmp", },
 
Quoted 5 lines

drivers/cpufreq/cpufreq-dt-platdev.c line 100

Quoted 3 lines
drivers/cpufreq/cpufreq-dt-platdev.c +3 -0
+       { .compatible = "qcom,msm8996", },
+       { .compatible = "qcom,apq8096", },
+

Why can't we base it on the kryocc node being present?

This could be good idea, if I would writing a platform specific cpufreq driver, which may be a future option.

Quoted 2 lines

Or even populate
the cpufreq-dt from the kryocc driver?

There is a problem that during the clock probe the OPP table still doesn't exist.

maintainer
#35 lore raw

PATCH v3 9/10 DT: QCOM: Add cpufreq-dt to msm8996

Quoting ilialin at codeaurora.org (2018-03-20 06:46:19)

Quoted 11 lines
Quoted 11 lines

From: Stephen Boyd <[email protected]>
Quoting Ilia Lin (2018-02-14 05:59:51)

Quoted 9 lines
drivers/cpufreq/cpufreq-dt-platdev.c +0 -0
index 3b585e4..b6cd0ae 100644
@@ -95,6 +95,9 @@
        { .compatible = "xlnx,zynq-7000", },
        { .compatible = "xlnx,zynqmp", },
 
Quoted 6 lines
Quoted 5 lines

drivers/cpufreq/cpufreq-dt-platdev.c line 100

Quoted 3 lines
drivers/cpufreq/cpufreq-dt-platdev.c +3 -0
+       { .compatible = "qcom,msm8996", },
+       { .compatible = "qcom,apq8096", },
+

Why can't we base it on the kryocc node being present?

This could be good idea, if I would writing a platform specific cpufreq driver, which may be a future option.

Well maybe cpufreq-dt can also look at the cpus nodes for a cpu with a certain type (in this case kryo). Then we can add cpufreq dt based on that CPU node being there.

Quoted 3 lines
Quoted 2 lines

Or even populate
the cpufreq-dt from the kryocc driver?

There is a problem that during the clock probe the OPP table still doesn't exist.

The OPP table is in DT? Why doesn't it exist?

#36 lore raw

PATCH v3 9/10 DT: QCOM: Add cpufreq-dt to msm8996

Understood, what you mean. I assumed that the cpufreq-dt is generic driver, and adding architecture specific code to it is no not correct from architectural point of view. Anyway, I'm considering adding a platform specific cpufreq driver, which will handle the efuse data as well.

Meanwhile this is the way to use the generic driver.

Quoted 41 lines

-----Original Message-----
From: Stephen Boyd <[email protected]>
Sent: Tuesday, March 20, 2018 22:06
To: ilialin at codeaurora.org; linux-arm-kernel at lists.infradead.org; linux-arm- msm at vger.kernel.org; linux-clk at vger.kernel.org; sboyd at codeaurora.org
Cc: mark.rutland at arm.com; devicetree at vger.kernel.org;
rnayak at codeaurora.org; robh at kernel.org; will.deacon at arm.com; amit.kucheria at linaro.org; tfinkel at codeaurora.org; nicolas.dechesne at linaro.org; celster at codeaurora.org
Subject: RE: [PATCH v3 09/10] DT: QCOM: Add cpufreq-dt to msm8996

Quoting ilialin at codeaurora.org (2018-03-20 06:46:19)

Quoted 11 lines
Quoted 11 lines

From: Stephen Boyd <[email protected]> Quoting Ilia Lin (2018-02-14 05:59:51)

Quoted 9 lines
drivers/cpufreq/cpufreq-dt-platdev.c +0 -0
index 3b585e4..b6cd0ae 100644
@@ -95,6 +95,9 @@
        { .compatible = "xlnx,zynq-7000", },
        { .compatible = "xlnx,zynqmp", },
 
Quoted 6 lines
Quoted 5 lines

drivers/cpufreq/cpufreq-dt-platdev.c line 100

Quoted 3 lines
drivers/cpufreq/cpufreq-dt-platdev.c +3 -0
+       { .compatible = "qcom,msm8996", },
+       { .compatible = "qcom,apq8096", },
+

Why can't we base it on the kryocc node being present?

This could be good idea, if I would writing a platform specific cpufreq driver,

which may be a future option.

Well maybe cpufreq-dt can also look at the cpus nodes for a cpu with a certain type (in this case kryo). Then we can add cpufreq dt based on that CPU node being there.

Quoted 3 lines
Quoted 2 lines

Or even populate
the cpufreq-dt from the kryocc driver?

There is a problem that during the clock probe the OPP table still doesn't

exist.

The OPP table is in DT? Why doesn't it exist?

maintainer
#37 lore raw

PATCH v3 9/10 DT: QCOM: Add cpufreq-dt to msm8996

Quoting ilialin at codeaurora.org (2018-03-20 13:34:04)

Quoted 4 lines

Understood, what you mean. I assumed that the cpufreq-dt is generic driver, and adding architecture specific code to it is no not correct from architectural point of view. Anyway, I'm considering adding a platform specific cpufreq driver, which will handle the efuse data as well.

Meanwhile this is the way to use the generic driver.

You'll need to Cc Viresh Kumar, who can comment further on cpufreq-dt. I wasn't recommending adding architecture specific code to cpufreq-dt, but at least updating how it handles CPU clk on/off state around hotplug would be good to do.

author
#38 lore raw

PATCH v3 10/10 DT: QCOM: Add thermal mitigation to msm8996

In reply to Ilia Lin

Add thermal mitigation configuration to msm8996. With the cpufreq-dt OPP table the CPU frequency may be scaled and therefore throttled by the thermal config.

---
 arch/arm64/boot/dts/qcom/msm8996.dtsi | 98 +++++++++++++++++++++++++++++++----
 1 file changed, 87 insertions(+), 11 deletions(-)
arch/arm64/boot/dts/qcom/msm8996.dtsi +87 -11
index 0359197..1df5b6f 100644
@@ -14,6 +14,7 @@
 #include <dt-bindings/clock/qcom,gcc-msm8996.h>
 #include <dt-bindings/clock/qcom,mmcc-msm8996.h>
 #include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8996";
@@ -88,6 +89,10 @@
 			enable-method = "psci";
 			clocks = <&kryocc 0>;
 			operating-points-v2 = <&cluster0_opp>;
+			/* cooling options */
+			cooling-min-level = <0>;
+			cooling-max-level = <15>;
+			#cooling-cells = <2>;
 			next-level-cache = <&L2_0>;
 			L2_0: l2-cache {
 			      compatible = "cache";
@@ -102,6 +107,10 @@
 			enable-method = "psci";
 			clocks = <&kryocc 0>;
 			operating-points-v2 = <&cluster0_opp>;
+			/* cooling options */
+			cooling-min-level = <0>;
+			cooling-max-level = <15>;
+			#cooling-cells = <2>;
 			next-level-cache = <&L2_0>;
 		};
 
@@ -112,6 +121,10 @@
 			enable-method = "psci";
 			clocks = <&kryocc 1>;
 			operating-points-v2 = <&cluster1_opp>;
+			/* cooling options */
+			cooling-min-level = <0>;
+			cooling-max-level = <15>;
+			#cooling-cells = <2>;
 			next-level-cache = <&L2_1>;
 			L2_1: l2-cache {
 			      compatible = "cache";
@@ -126,6 +139,10 @@
 			enable-method = "psci";
 			clocks = <&kryocc 1>;
 			operating-points-v2 = <&cluster1_opp>;
+			/* cooling options */
+			cooling-min-level = <0>;
+			cooling-max-level = <15>;
+			#cooling-cells = <2>;
 			next-level-cache = <&L2_1>;
 		};
 
@@ -336,18 +353,33 @@
 			thermal-sensors = <&tsens0 3>;
 
 			trips {
-				cpu_alert0: trip0 {
+				cpu_alert0: cpu_alert0 {
 					temperature = <75000>;
 					hysteresis = <2000>;
+					type = "active";
+				};
+				cpu_warn0: cpu_warn0 {
+					temperature = <90000>;
+					hysteresis = <2000>;
 					type = "passive";
 				};
-
-				cpu_crit0: trip1 {
+				cpu_crit0: cpu_crit0 {
 					temperature = <110000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device = <&CPU0 THERMAL_NO_LIMIT 7>;
+				};
+				map1 {
+					trip = <&cpu_warn0>;
+					cooling-device = <&CPU0 8 THERMAL_NO_LIMIT>;
+				};
+			};
 		};
 
 		cpu-thermal1 {
@@ -357,18 +389,33 @@
 			thermal-sensors = <&tsens0 5>;
 
 			trips {
-				cpu_alert1: trip0 {
+				cpu_alert1: cpu_alert1 {
 					temperature = <75000>;
 					hysteresis = <2000>;
+					type = "active";
+				};
+				cpu_warn1: cpu_warn1 {
+					temperature = <90000>;
+					hysteresis = <2000>;
 					type = "passive";
 				};
-
-				cpu_crit1: trip1 {
+				cpu_crit1: cpu_crit1 {
 					temperature = <110000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert1>;
+					cooling-device = <&CPU0 THERMAL_NO_LIMIT 7>;
+				};
+				map1 {
+					trip = <&cpu_warn1>;
+					cooling-device = <&CPU0 8 THERMAL_NO_LIMIT>;
+				};
+			};
 		};
 
 		cpu-thermal2 {
@@ -378,18 +425,32 @@
 			thermal-sensors = <&tsens0 8>;
 
 			trips {
-				cpu_alert2: trip0 {
+				cpu_alert2: cpu_alert2 {
 					temperature = <75000>;
 					hysteresis = <2000>;
+					type = "active";
+				};
+				cpu_warn2: cpu_warn2 {
+					temperature = <90000>;
+					hysteresis = <2000>;
 					type = "passive";
 				};
-
-				cpu_crit2: trip1 {
+				cpu_crit2: cpu_crit2 {
 					temperature = <110000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert2>;
+					cooling-device = <&CPU2 THERMAL_NO_LIMIT 7>;
+				};
+				map1 {
+					trip = <&cpu_warn2>;
+					cooling-device = <&CPU2 8 THERMAL_NO_LIMIT>;
+				};
+			};
 		};
 
 		cpu-thermal3 {
@@ -399,18 +460,33 @@
 			thermal-sensors = <&tsens0 10>;
 
 			trips {
-				cpu_alert3: trip0 {
+				cpu_alert3: cpu_alert3 {
 					temperature = <75000>;
 					hysteresis = <2000>;
+					type = "active";
+				};
+				cpu_warn3: cpu_warn3 {
+					temperature = <90000>;
+					hysteresis = <2000>;
 					type = "passive";
 				};
-
 				cpu_crit3: trip1 {
 					temperature = <110000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert3>;
+					cooling-device = <&CPU2 THERMAL_NO_LIMIT 7>;
+				};
+				map1 {
+					trip = <&cpu_warn3>;
+					cooling-device = <&CPU2 8 THERMAL_NO_LIMIT>;
+				};
+			};
 		};
 	};
 
Signature · 1 line
1.9.1