This patchset has been merged upstream.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
+++ /dev/null
-From 36d68f64c411e09788687d5919886aadeb92adca Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:20 +0530
-Subject: [PATCH 01/12] ARM: Add Krait L2 register accessor functions
-
-Krait CPUs have a handful of L2 cache controller registers that
-live behind a cp15 based indirection register. First you program
-the indirection register (l2cpselr) to point the L2 'window'
-register (l2cpdr) at what you want to read/write. Then you
-read/write the 'window' register to do what you want. The
-l2cpselr register is not banked per-cpu so we must lock around
-accesses to it to prevent other CPUs from re-pointing l2cpdr
-underneath us.
-
-Cc: Mark Rutland <mark.rutland@arm.com>
-Cc: Russell King <linux@arm.linux.org.uk>
-Acked-by: Bjorn Andersson <bjorn.andersson@linaro.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- arch/arm/common/Kconfig | 3 ++
- arch/arm/common/Makefile | 1 +
- arch/arm/common/krait-l2-accessors.c | 48 +++++++++++++++++++++++
- arch/arm/include/asm/krait-l2-accessors.h | 9 +++++
- 4 files changed, 61 insertions(+)
- create mode 100644 arch/arm/common/krait-l2-accessors.c
- create mode 100644 arch/arm/include/asm/krait-l2-accessors.h
-
---- a/arch/arm/common/Kconfig
-+++ b/arch/arm/common/Kconfig
-@@ -7,6 +7,9 @@ config DMABOUNCE
- bool
- select ZONE_DMA
-
-+config KRAIT_L2_ACCESSORS
-+ bool
-+
- config SHARP_LOCOMO
- bool
-
---- a/arch/arm/common/Makefile
-+++ b/arch/arm/common/Makefile
-@@ -7,6 +7,7 @@ obj-y += firmware.o
-
- obj-$(CONFIG_SA1111) += sa1111.o
- obj-$(CONFIG_DMABOUNCE) += dmabounce.o
-+obj-$(CONFIG_KRAIT_L2_ACCESSORS) += krait-l2-accessors.o
- obj-$(CONFIG_SHARP_LOCOMO) += locomo.o
- obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
- obj-$(CONFIG_SHARP_SCOOP) += scoop.o
---- /dev/null
-+++ b/arch/arm/common/krait-l2-accessors.c
-@@ -0,0 +1,48 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
-+
-+#include <linux/spinlock.h>
-+#include <linux/export.h>
-+
-+#include <asm/barrier.h>
-+#include <asm/krait-l2-accessors.h>
-+
-+static DEFINE_RAW_SPINLOCK(krait_l2_lock);
-+
-+void krait_set_l2_indirect_reg(u32 addr, u32 val)
-+{
-+ unsigned long flags;
-+
-+ raw_spin_lock_irqsave(&krait_l2_lock, flags);
-+ /*
-+ * Select the L2 window by poking l2cpselr, then write to the window
-+ * via l2cpdr.
-+ */
-+ asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
-+ isb();
-+ asm volatile ("mcr p15, 3, %0, c15, c0, 7 @ l2cpdr" : : "r" (val));
-+ isb();
-+
-+ raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
-+}
-+EXPORT_SYMBOL(krait_set_l2_indirect_reg);
-+
-+u32 krait_get_l2_indirect_reg(u32 addr)
-+{
-+ u32 val;
-+ unsigned long flags;
-+
-+ raw_spin_lock_irqsave(&krait_l2_lock, flags);
-+ /*
-+ * Select the L2 window by poking l2cpselr, then read from the window
-+ * via l2cpdr.
-+ */
-+ asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
-+ isb();
-+ asm volatile ("mrc p15, 3, %0, c15, c0, 7 @ l2cpdr" : "=r" (val));
-+
-+ raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
-+
-+ return val;
-+}
-+EXPORT_SYMBOL(krait_get_l2_indirect_reg);
---- /dev/null
-+++ b/arch/arm/include/asm/krait-l2-accessors.h
-@@ -0,0 +1,9 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+#ifndef __ASMARM_KRAIT_L2_ACCESSORS_H
-+#define __ASMARM_KRAIT_L2_ACCESSORS_H
-+
-+extern void krait_set_l2_indirect_reg(u32 addr, u32 val);
-+extern u32 krait_get_l2_indirect_reg(u32 addr);
-+
-+#endif
+++ /dev/null
-From b3f2f10693aadeacf83ab5be03810941a4b77612 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:21 +0530
-Subject: [PATCH 02/12] clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
-
-HFPLLs are the main frequency source for Krait CPU clocks. Add
-support for changing the rate of these PLLs.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/clk-hfpll.c | 244 +++++++++++++++++++++++++++++++++++
- drivers/clk/qcom/clk-hfpll.h | 44 +++++++
- 3 files changed, 289 insertions(+)
- create mode 100644 drivers/clk/qcom/clk-hfpll.c
- create mode 100644 drivers/clk/qcom/clk-hfpll.h
-
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -11,6 +11,7 @@ clk-qcom-y += clk-branch.o
- clk-qcom-y += clk-regmap-divider.o
- clk-qcom-y += clk-regmap-mux.o
- clk-qcom-y += clk-regmap-mux-div.o
-+clk-qcom-y += clk-hfpll.o
- clk-qcom-y += reset.o
- clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
-
---- /dev/null
-+++ b/drivers/clk/qcom/clk-hfpll.c
-@@ -0,0 +1,244 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
-+
-+#include <linux/kernel.h>
-+#include <linux/export.h>
-+#include <linux/regmap.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/clk-provider.h>
-+#include <linux/spinlock.h>
-+
-+#include "clk-regmap.h"
-+#include "clk-hfpll.h"
-+
-+#define PLL_OUTCTRL BIT(0)
-+#define PLL_BYPASSNL BIT(1)
-+#define PLL_RESET_N BIT(2)
-+
-+/* Initialize a HFPLL at a given rate and enable it. */
-+static void __clk_hfpll_init_once(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+
-+ if (likely(h->init_done))
-+ return;
-+
-+ /* Configure PLL parameters for integer mode. */
-+ if (hd->config_val)
-+ regmap_write(regmap, hd->config_reg, hd->config_val);
-+ regmap_write(regmap, hd->m_reg, 0);
-+ regmap_write(regmap, hd->n_reg, 1);
-+
-+ if (hd->user_reg) {
-+ u32 regval = hd->user_val;
-+ unsigned long rate;
-+
-+ rate = clk_hw_get_rate(hw);
-+
-+ /* Pick the right VCO. */
-+ if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
-+ regval |= hd->user_vco_mask;
-+ regmap_write(regmap, hd->user_reg, regval);
-+ }
-+
-+ if (hd->droop_reg)
-+ regmap_write(regmap, hd->droop_reg, hd->droop_val);
-+
-+ h->init_done = true;
-+}
-+
-+static void __clk_hfpll_enable(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 val;
-+
-+ __clk_hfpll_init_once(hw);
-+
-+ /* Disable PLL bypass mode. */
-+ regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);
-+
-+ /*
-+ * H/W requires a 5us delay between disabling the bypass and
-+ * de-asserting the reset. Delay 10us just to be safe.
-+ */
-+ udelay(10);
-+
-+ /* De-assert active-low PLL reset. */
-+ regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
-+
-+ /* Wait for PLL to lock. */
-+ if (hd->status_reg) {
-+ do {
-+ regmap_read(regmap, hd->status_reg, &val);
-+ } while (!(val & BIT(hd->lock_bit)));
-+ } else {
-+ udelay(60);
-+ }
-+
-+ /* Enable PLL output. */
-+ regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
-+}
-+
-+/* Enable an already-configured HFPLL. */
-+static int clk_hfpll_enable(struct clk_hw *hw)
-+{
-+ unsigned long flags;
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 mode;
-+
-+ spin_lock_irqsave(&h->lock, flags);
-+ regmap_read(regmap, hd->mode_reg, &mode);
-+ if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
-+ __clk_hfpll_enable(hw);
-+ spin_unlock_irqrestore(&h->lock, flags);
-+
-+ return 0;
-+}
-+
-+static void __clk_hfpll_disable(struct clk_hfpll *h)
-+{
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+
-+ /*
-+ * Disable the PLL output, disable test mode, enable the bypass mode,
-+ * and assert the reset.
-+ */
-+ regmap_update_bits(regmap, hd->mode_reg,
-+ PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
-+}
-+
-+static void clk_hfpll_disable(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&h->lock, flags);
-+ __clk_hfpll_disable(h);
-+ spin_unlock_irqrestore(&h->lock, flags);
-+}
-+
-+static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long *parent_rate)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ unsigned long rrate;
-+
-+ rate = clamp(rate, hd->min_rate, hd->max_rate);
-+
-+ rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate;
-+ if (rrate > hd->max_rate)
-+ rrate -= *parent_rate;
-+
-+ return rrate;
-+}
-+
-+/*
-+ * For optimization reasons, assumes no downstream clocks are actively using
-+ * it.
-+ */
-+static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ unsigned long flags;
-+ u32 l_val, val;
-+ bool enabled;
-+
-+ l_val = rate / parent_rate;
-+
-+ spin_lock_irqsave(&h->lock, flags);
-+
-+ enabled = __clk_is_enabled(hw->clk);
-+ if (enabled)
-+ __clk_hfpll_disable(h);
-+
-+ /* Pick the right VCO. */
-+ if (hd->user_reg && hd->user_vco_mask) {
-+ regmap_read(regmap, hd->user_reg, &val);
-+ if (rate <= hd->low_vco_max_rate)
-+ val &= ~hd->user_vco_mask;
-+ else
-+ val |= hd->user_vco_mask;
-+ regmap_write(regmap, hd->user_reg, val);
-+ }
-+
-+ regmap_write(regmap, hd->l_reg, l_val);
-+
-+ if (enabled)
-+ __clk_hfpll_enable(hw);
-+
-+ spin_unlock_irqrestore(&h->lock, flags);
-+
-+ return 0;
-+}
-+
-+static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 l_val;
-+
-+ regmap_read(regmap, hd->l_reg, &l_val);
-+
-+ return l_val * parent_rate;
-+}
-+
-+static void clk_hfpll_init(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 mode, status;
-+
-+ regmap_read(regmap, hd->mode_reg, &mode);
-+ if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
-+ __clk_hfpll_init_once(hw);
-+ return;
-+ }
-+
-+ if (hd->status_reg) {
-+ regmap_read(regmap, hd->status_reg, &status);
-+ if (!(status & BIT(hd->lock_bit))) {
-+ WARN(1, "HFPLL %s is ON, but not locked!\n",
-+ __clk_get_name(hw->clk));
-+ clk_hfpll_disable(hw);
-+ __clk_hfpll_init_once(hw);
-+ }
-+ }
-+}
-+
-+static int hfpll_is_enabled(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 mode;
-+
-+ regmap_read(regmap, hd->mode_reg, &mode);
-+ mode &= 0x7;
-+ return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
-+}
-+
-+const struct clk_ops clk_ops_hfpll = {
-+ .enable = clk_hfpll_enable,
-+ .disable = clk_hfpll_disable,
-+ .is_enabled = hfpll_is_enabled,
-+ .round_rate = clk_hfpll_round_rate,
-+ .set_rate = clk_hfpll_set_rate,
-+ .recalc_rate = clk_hfpll_recalc_rate,
-+ .init = clk_hfpll_init,
-+};
-+EXPORT_SYMBOL_GPL(clk_ops_hfpll);
---- /dev/null
-+++ b/drivers/clk/qcom/clk-hfpll.h
-@@ -0,0 +1,44 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+#ifndef __QCOM_CLK_HFPLL_H__
-+#define __QCOM_CLK_HFPLL_H__
-+
-+#include <linux/clk-provider.h>
-+#include <linux/spinlock.h>
-+#include "clk-regmap.h"
-+
-+struct hfpll_data {
-+ u32 mode_reg;
-+ u32 l_reg;
-+ u32 m_reg;
-+ u32 n_reg;
-+ u32 user_reg;
-+ u32 droop_reg;
-+ u32 config_reg;
-+ u32 status_reg;
-+ u8 lock_bit;
-+
-+ u32 droop_val;
-+ u32 config_val;
-+ u32 user_val;
-+ u32 user_vco_mask;
-+ unsigned long low_vco_max_rate;
-+
-+ unsigned long min_rate;
-+ unsigned long max_rate;
-+};
-+
-+struct clk_hfpll {
-+ struct hfpll_data const *d;
-+ int init_done;
-+
-+ struct clk_regmap clkr;
-+ spinlock_t lock;
-+};
-+
-+#define to_clk_hfpll(_hw) \
-+ container_of(to_clk_regmap(_hw), struct clk_hfpll, clkr)
-+
-+extern const struct clk_ops clk_ops_hfpll;
-+
-+#endif
+++ /dev/null
-From cb546b797a0da4dbb1a0c76a2a357921887b6189 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:22 +0530
-Subject: [PATCH 03/12] clk: qcom: Add HFPLL driver
-
-On some devices (MSM8974 for example), the HFPLLs are
-instantiated within the Krait processor subsystem as separate
-register regions. Add a driver for these PLLs so that we can
-provide HFPLL clocks for use by the system.
-
-Cc: <devicetree@vger.kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/qcom/Kconfig | 8 ++++
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/hfpll.c | 96 +++++++++++++++++++++++++++++++++++++++
- 3 files changed, 105 insertions(+)
- create mode 100644 drivers/clk/qcom/hfpll.c
-
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -272,3 +272,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 QCOM_HFPLL
-+ tristate "High-Frequency PLL (HFPLL) Clock Controller"
-+ depends on COMMON_CLK_QCOM
-+ help
-+ Support for the high-frequency PLLs present on Qualcomm devices.
-+ Say Y if you want to support CPU frequency scaling on devices
-+ such as MSM8974, APQ8084, etc.
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -44,3 +44,4 @@ obj-$(CONFIG_SDM_DISPCC_845) += dispcc-s
- obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
- obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
- obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
-+obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
---- /dev/null
-+++ b/drivers/clk/qcom/hfpll.c
-@@ -0,0 +1,96 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/of.h>
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/regmap.h>
-+
-+#include "clk-regmap.h"
-+#include "clk-hfpll.h"
-+
-+static const struct hfpll_data hdata = {
-+ .mode_reg = 0x00,
-+ .l_reg = 0x04,
-+ .m_reg = 0x08,
-+ .n_reg = 0x0c,
-+ .user_reg = 0x10,
-+ .config_reg = 0x14,
-+ .config_val = 0x430405d,
-+ .status_reg = 0x1c,
-+ .lock_bit = 16,
-+
-+ .user_val = 0x8,
-+ .user_vco_mask = 0x100000,
-+ .low_vco_max_rate = 1248000000,
-+ .min_rate = 537600000UL,
-+ .max_rate = 2900000000UL,
-+};
-+
-+static const struct of_device_id qcom_hfpll_match_table[] = {
-+ { .compatible = "qcom,hfpll" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table);
-+
-+static const struct regmap_config hfpll_regmap_config = {
-+ .reg_bits = 32,
-+ .reg_stride = 4,
-+ .val_bits = 32,
-+ .max_register = 0x30,
-+ .fast_io = true,
-+};
-+
-+static int qcom_hfpll_probe(struct platform_device *pdev)
-+{
-+ struct resource *res;
-+ struct device *dev = &pdev->dev;
-+ void __iomem *base;
-+ struct regmap *regmap;
-+ struct clk_hfpll *h;
-+ struct clk_init_data init = {
-+ .parent_names = (const char *[]){ "xo" },
-+ .num_parents = 1,
-+ .ops = &clk_ops_hfpll,
-+ };
-+
-+ h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
-+ if (!h)
-+ 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 = devm_regmap_init_mmio(&pdev->dev, base, &hfpll_regmap_config);
-+ if (IS_ERR(regmap))
-+ return PTR_ERR(regmap);
-+
-+ if (of_property_read_string_index(dev->of_node, "clock-output-names",
-+ 0, &init.name))
-+ return -ENODEV;
-+
-+ h->d = &hdata;
-+ h->clkr.hw.init = &init;
-+ spin_lock_init(&h->lock);
-+
-+ return devm_clk_register_regmap(&pdev->dev, &h->clkr);
-+}
-+
-+static struct platform_driver qcom_hfpll_driver = {
-+ .probe = qcom_hfpll_probe,
-+ .driver = {
-+ .name = "qcom-hfpll",
-+ .of_match_table = qcom_hfpll_match_table,
-+ },
-+};
-+module_platform_driver(qcom_hfpll_driver);
-+
-+MODULE_DESCRIPTION("QCOM HFPLL Clock Driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:qcom-hfpll");
+++ /dev/null
-From 1f924faa8b1e4789ecc06ed0dd58ca3487c89012 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:23 +0530
-Subject: [PATCH 04/12] dt-bindings: clock: Document qcom,hfpll
-
-Adds bindings document for qcom,hfpll instantiated within
-the Krait processor subsystem as separate register region.
-
-Reviewed-by: Rob Herring <robh@kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- .../devicetree/bindings/clock/qcom,hfpll.txt | 60 +++++++++++++++++++
- 1 file changed, 60 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/clock/qcom,hfpll.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/clock/qcom,hfpll.txt
-@@ -0,0 +1,60 @@
-+High-Frequency PLL (HFPLL)
-+
-+PROPERTIES
-+
-+- compatible:
-+ Usage: required
-+ Value type: <string>:
-+ shall contain only one of the following. The generic
-+ compatible "qcom,hfpll" should be also included.
-+
-+ "qcom,hfpll-ipq8064", "qcom,hfpll"
-+ "qcom,hfpll-apq8064", "qcom,hfpll"
-+ "qcom,hfpll-msm8974", "qcom,hfpll"
-+ "qcom,hfpll-msm8960", "qcom,hfpll"
-+
-+- reg:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: address and size of HPLL registers. An optional second
-+ element specifies the address and size of the alias
-+ register region.
-+
-+- clocks:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: reference to the xo clock.
-+
-+- clock-names:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: must be "xo".
-+
-+- clock-output-names:
-+ Usage: required
-+ Value type: <string>
-+ Definition: Name of the PLL. Typically hfpllX where X is a CPU number
-+ starting at 0. Otherwise hfpll_Y where Y is more specific
-+ such as "l2".
-+
-+Example:
-+
-+1) An HFPLL for the L2 cache.
-+
-+ clock-controller@f9016000 {
-+ compatible = "qcom,hfpll-ipq8064", "qcom,hfpll";
-+ reg = <0xf9016000 0x30>;
-+ clocks = <&xo_board>;
-+ clock-names = "xo";
-+ clock-output-names = "hfpll_l2";
-+ };
-+
-+2) An HFPLL for CPU0. This HFPLL has the alias register region.
-+
-+ clock-controller@f908a000 {
-+ compatible = "qcom,hfpll-ipq8064", "qcom,hfpll";
-+ reg = <0xf908a000 0x30>, <0xf900a000 0x30>;
-+ clocks = <&xo_board>;
-+ clock-names = "xo";
-+ clock-output-names = "hfpll0";
-+ };
+++ /dev/null
-From 72ad7207954dd622a662ba884dc6c30a820123f2 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:24 +0530
-Subject: [PATCH 05/12] clk: qcom: Add MSM8960/APQ8064's HFPLLs
-
-Describe the HFPLLs present on MSM8960 and APQ8064 devices.
-
-Acked-by: Rob Herring <robh@kernel.org> (bindings)
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/qcom/gcc-msm8960.c | 172 +++++++++++++++++++
- include/dt-bindings/clock/qcom,gcc-msm8960.h | 2 +
- 2 files changed, 174 insertions(+)
-
---- a/drivers/clk/qcom/gcc-msm8960.c
-+++ b/drivers/clk/qcom/gcc-msm8960.c
-@@ -30,6 +30,7 @@
- #include "clk-pll.h"
- #include "clk-rcg.h"
- #include "clk-branch.h"
-+#include "clk-hfpll.h"
- #include "reset.h"
-
- static struct clk_pll pll3 = {
-@@ -86,6 +87,164 @@ static struct clk_regmap pll8_vote = {
- },
- };
-
-+static struct hfpll_data hfpll0_data = {
-+ .mode_reg = 0x3200,
-+ .l_reg = 0x3208,
-+ .m_reg = 0x320c,
-+ .n_reg = 0x3210,
-+ .config_reg = 0x3204,
-+ .status_reg = 0x321c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3214,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll0 = {
-+ .d = &hfpll0_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll0",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
-+};
-+
-+static struct hfpll_data hfpll1_8064_data = {
-+ .mode_reg = 0x3240,
-+ .l_reg = 0x3248,
-+ .m_reg = 0x324c,
-+ .n_reg = 0x3250,
-+ .config_reg = 0x3244,
-+ .status_reg = 0x325c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3254,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct hfpll_data hfpll1_data = {
-+ .mode_reg = 0x3300,
-+ .l_reg = 0x3308,
-+ .m_reg = 0x330c,
-+ .n_reg = 0x3310,
-+ .config_reg = 0x3304,
-+ .status_reg = 0x331c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3314,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll1 = {
-+ .d = &hfpll1_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll1",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
-+};
-+
-+static struct hfpll_data hfpll2_data = {
-+ .mode_reg = 0x3280,
-+ .l_reg = 0x3288,
-+ .m_reg = 0x328c,
-+ .n_reg = 0x3290,
-+ .config_reg = 0x3284,
-+ .status_reg = 0x329c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3294,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll2 = {
-+ .d = &hfpll2_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll2",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll2.lock),
-+};
-+
-+static struct hfpll_data hfpll3_data = {
-+ .mode_reg = 0x32c0,
-+ .l_reg = 0x32c8,
-+ .m_reg = 0x32cc,
-+ .n_reg = 0x32d0,
-+ .config_reg = 0x32c4,
-+ .status_reg = 0x32dc,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x32d4,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll3 = {
-+ .d = &hfpll3_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll3",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll3.lock),
-+};
-+
-+static struct hfpll_data hfpll_l2_8064_data = {
-+ .mode_reg = 0x3300,
-+ .l_reg = 0x3308,
-+ .m_reg = 0x330c,
-+ .n_reg = 0x3310,
-+ .config_reg = 0x3304,
-+ .status_reg = 0x331c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3314,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct hfpll_data hfpll_l2_data = {
-+ .mode_reg = 0x3400,
-+ .l_reg = 0x3408,
-+ .m_reg = 0x340c,
-+ .n_reg = 0x3410,
-+ .config_reg = 0x3404,
-+ .status_reg = 0x341c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3414,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll_l2 = {
-+ .d = &hfpll_l2_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll_l2",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
-+};
-+
- static struct clk_pll pll14 = {
- .l_reg = 0x31c4,
- .m_reg = 0x31c8,
-@@ -3107,6 +3266,9 @@ static struct clk_regmap *gcc_msm8960_cl
- [PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr,
- [PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr,
- [RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr,
-+ [PLL9] = &hfpll0.clkr,
-+ [PLL10] = &hfpll1.clkr,
-+ [PLL12] = &hfpll_l2.clkr,
- };
-
- static const struct qcom_reset_map gcc_msm8960_resets[] = {
-@@ -3318,6 +3480,11 @@ static struct clk_regmap *gcc_apq8064_cl
- [PMIC_ARB1_H_CLK] = &pmic_arb1_h_clk.clkr,
- [PMIC_SSBI2_CLK] = &pmic_ssbi2_clk.clkr,
- [RPM_MSG_RAM_H_CLK] = &rpm_msg_ram_h_clk.clkr,
-+ [PLL9] = &hfpll0.clkr,
-+ [PLL10] = &hfpll1.clkr,
-+ [PLL12] = &hfpll_l2.clkr,
-+ [PLL16] = &hfpll2.clkr,
-+ [PLL17] = &hfpll3.clkr,
- };
-
- static const struct qcom_reset_map gcc_apq8064_resets[] = {
-@@ -3477,6 +3644,11 @@ static int gcc_msm8960_probe(struct plat
- if (ret)
- return ret;
-
-+ if (match->data == &gcc_apq8064_desc) {
-+ hfpll1.d = &hfpll1_8064_data;
-+ hfpll_l2.d = &hfpll_l2_8064_data;
-+ }
-+
- tsens = platform_device_register_data(&pdev->dev, "qcom-tsens", -1,
- NULL, 0);
- if (IS_ERR(tsens))
---- a/include/dt-bindings/clock/qcom,gcc-msm8960.h
-+++ b/include/dt-bindings/clock/qcom,gcc-msm8960.h
-@@ -319,5 +319,7 @@
- #define CE3_SRC 303
- #define CE3_CORE_CLK 304
- #define CE3_H_CLK 305
-+#define PLL16 306
-+#define PLL17 307
-
- #endif
+++ /dev/null
-From 1f79131bfd512f322c16b58dca581ce39beafab9 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:25 +0530
-Subject: [PATCH 06/12] clk: qcom: Add IPQ806X's HFPLLs
-
-Describe the HFPLLs present on IPQ806X devices.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/qcom/gcc-ipq806x.c | 82 ++++++++++++++++++++++++++++++++++
- 1 file changed, 82 insertions(+)
-
---- a/drivers/clk/qcom/gcc-ipq806x.c
-+++ b/drivers/clk/qcom/gcc-ipq806x.c
-@@ -30,6 +30,7 @@
- #include "clk-pll.h"
- #include "clk-rcg.h"
- #include "clk-branch.h"
-+#include "clk-hfpll.h"
- #include "reset.h"
-
- static struct clk_pll pll0 = {
-@@ -113,6 +114,84 @@ static struct clk_regmap pll8_vote = {
- },
- };
-
-+static struct hfpll_data hfpll0_data = {
-+ .mode_reg = 0x3200,
-+ .l_reg = 0x3208,
-+ .m_reg = 0x320c,
-+ .n_reg = 0x3210,
-+ .config_reg = 0x3204,
-+ .status_reg = 0x321c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3214,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll0 = {
-+ .d = &hfpll0_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll0",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
-+};
-+
-+static struct hfpll_data hfpll1_data = {
-+ .mode_reg = 0x3240,
-+ .l_reg = 0x3248,
-+ .m_reg = 0x324c,
-+ .n_reg = 0x3250,
-+ .config_reg = 0x3244,
-+ .status_reg = 0x325c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3314,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll1 = {
-+ .d = &hfpll1_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll1",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
-+};
-+
-+static struct hfpll_data hfpll_l2_data = {
-+ .mode_reg = 0x3300,
-+ .l_reg = 0x3308,
-+ .m_reg = 0x330c,
-+ .n_reg = 0x3310,
-+ .config_reg = 0x3304,
-+ .status_reg = 0x331c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3314,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll_l2 = {
-+ .d = &hfpll_l2_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll_l2",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
-+};
-+
- static struct clk_pll pll14 = {
- .l_reg = 0x31c4,
- .m_reg = 0x31c8,
-@@ -2798,6 +2877,9 @@ static struct clk_regmap *gcc_ipq806x_cl
- [UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
- [NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
- [NSSTCM_CLK] = &nss_tcm_clk.clkr,
-+ [PLL9] = &hfpll0.clkr,
-+ [PLL10] = &hfpll1.clkr,
-+ [PLL12] = &hfpll_l2.clkr,
- };
-
- static const struct qcom_reset_map gcc_ipq806x_resets[] = {
+++ /dev/null
-From 4d7dc77babfef1d6cb8fd825e2f17dc3384c3272 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:26 +0530
-Subject: [PATCH 07/12] clk: qcom: Add support for Krait clocks
-
-The Krait clocks are made up of a series of muxes and a divider
-that choose between a fixed rate clock and dedicated HFPLLs for
-each CPU. Instead of using mmio accesses to remux parents, the
-Krait implementation exposes the remux control via cp15
-registers. Support these clocks.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-[sboyd@kernel.org: Move hidden config to top outside of the visible qcom
-config zone so that menuconfig looks nice]
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/qcom/Kconfig | 4 ++
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/clk-krait.c | 124 +++++++++++++++++++++++++++++++++++
- drivers/clk/qcom/clk-krait.h | 37 +++++++++++
- 4 files changed, 166 insertions(+)
- create mode 100644 drivers/clk/qcom/clk-krait.c
- create mode 100644 drivers/clk/qcom/clk-krait.h
-
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -1,3 +1,7 @@
-+config KRAIT_CLOCKS
-+ bool
-+ select KRAIT_L2_ACCESSORS
-+
- config QCOM_GDSC
- bool
- select PM_GENERIC_DOMAINS if PM
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -11,6 +11,7 @@ clk-qcom-y += clk-branch.o
- clk-qcom-y += clk-regmap-divider.o
- clk-qcom-y += clk-regmap-mux.o
- clk-qcom-y += clk-regmap-mux-div.o
-+clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
- clk-qcom-y += clk-hfpll.o
- clk-qcom-y += reset.o
- clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
---- /dev/null
-+++ b/drivers/clk/qcom/clk-krait.c
-@@ -0,0 +1,124 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/clk-provider.h>
-+#include <linux/spinlock.h>
-+
-+#include <asm/krait-l2-accessors.h>
-+
-+#include "clk-krait.h"
-+
-+/* Secondary and primary muxes share the same cp15 register */
-+static DEFINE_SPINLOCK(krait_clock_reg_lock);
-+
-+#define LPL_SHIFT 8
-+static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel)
-+{
-+ unsigned long flags;
-+ u32 regval;
-+
-+ spin_lock_irqsave(&krait_clock_reg_lock, flags);
-+ regval = krait_get_l2_indirect_reg(mux->offset);
-+ regval &= ~(mux->mask << mux->shift);
-+ regval |= (sel & mux->mask) << mux->shift;
-+ if (mux->lpl) {
-+ regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
-+ regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
-+ }
-+ krait_set_l2_indirect_reg(mux->offset, regval);
-+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
-+
-+ /* Wait for switch to complete. */
-+ mb();
-+ udelay(1);
-+}
-+
-+static int krait_mux_set_parent(struct clk_hw *hw, u8 index)
-+{
-+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
-+ u32 sel;
-+
-+ sel = clk_mux_reindex(index, mux->parent_map, 0);
-+ mux->en_mask = sel;
-+ /* Don't touch mux if CPU is off as it won't work */
-+ if (__clk_is_enabled(hw->clk))
-+ __krait_mux_set_sel(mux, sel);
-+
-+ return 0;
-+}
-+
-+static u8 krait_mux_get_parent(struct clk_hw *hw)
-+{
-+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
-+ u32 sel;
-+
-+ sel = krait_get_l2_indirect_reg(mux->offset);
-+ sel >>= mux->shift;
-+ sel &= mux->mask;
-+ mux->en_mask = sel;
-+
-+ return clk_mux_get_parent(hw, sel, mux->parent_map, 0);
-+}
-+
-+const struct clk_ops krait_mux_clk_ops = {
-+ .set_parent = krait_mux_set_parent,
-+ .get_parent = krait_mux_get_parent,
-+ .determine_rate = __clk_mux_determine_rate_closest,
-+};
-+EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
-+
-+/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
-+static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long *parent_rate)
-+{
-+ *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2);
-+ return DIV_ROUND_UP(*parent_rate, 2);
-+}
-+
-+static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct krait_div2_clk *d = to_krait_div2_clk(hw);
-+ unsigned long flags;
-+ u32 val;
-+ u32 mask = BIT(d->width) - 1;
-+
-+ if (d->lpl)
-+ mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift;
-+
-+ spin_lock_irqsave(&krait_clock_reg_lock, flags);
-+ val = krait_get_l2_indirect_reg(d->offset);
-+ val &= ~mask;
-+ krait_set_l2_indirect_reg(d->offset, val);
-+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
-+
-+ return 0;
-+}
-+
-+static unsigned long
-+krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
-+{
-+ struct krait_div2_clk *d = to_krait_div2_clk(hw);
-+ u32 mask = BIT(d->width) - 1;
-+ u32 div;
-+
-+ div = krait_get_l2_indirect_reg(d->offset);
-+ div >>= d->shift;
-+ div &= mask;
-+ div = (div + 1) * 2;
-+
-+ return DIV_ROUND_UP(parent_rate, div);
-+}
-+
-+const struct clk_ops krait_div2_clk_ops = {
-+ .round_rate = krait_div2_round_rate,
-+ .set_rate = krait_div2_set_rate,
-+ .recalc_rate = krait_div2_recalc_rate,
-+};
-+EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
---- /dev/null
-+++ b/drivers/clk/qcom/clk-krait.h
-@@ -0,0 +1,37 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+#ifndef __QCOM_CLK_KRAIT_H
-+#define __QCOM_CLK_KRAIT_H
-+
-+#include <linux/clk-provider.h>
-+
-+struct krait_mux_clk {
-+ unsigned int *parent_map;
-+ u32 offset;
-+ u32 mask;
-+ u32 shift;
-+ u32 en_mask;
-+ bool lpl;
-+
-+ struct clk_hw hw;
-+ struct notifier_block clk_nb;
-+};
-+
-+#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)
-+
-+extern const struct clk_ops krait_mux_clk_ops;
-+
-+struct krait_div2_clk {
-+ u32 offset;
-+ u8 width;
-+ u32 shift;
-+ bool lpl;
-+
-+ struct clk_hw hw;
-+};
-+
-+#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw)
-+
-+extern const struct clk_ops krait_div2_clk_ops;
-+
-+#endif
+++ /dev/null
-From 3ddc3564d3c9f097986bd4ccbe34152413811335 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:27 +0530
-Subject: [PATCH 08/12] clk: qcom: Add KPSS ACC/GCC driver
-
-The ACC and GCC regions present in KPSSv1 contain registers to
-control clocks and power to each Krait CPU and L2. For CPUfreq
-purposes probe these devices and expose a mux clock that chooses
-between PXO and PLL8.
-
-Cc: <devicetree@vger.kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/qcom/Kconfig | 8 ++++
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/kpss-xcc.c | 87 +++++++++++++++++++++++++++++++++++++
- 3 files changed, 96 insertions(+)
- create mode 100644 drivers/clk/qcom/kpss-xcc.c
-
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -284,3 +284,11 @@ config QCOM_HFPLL
- Support for the high-frequency PLLs present on Qualcomm devices.
- Say Y if you want to support CPU frequency scaling on devices
- such as MSM8974, APQ8084, etc.
-+
-+config KPSS_XCC
-+ tristate "KPSS Clock Controller"
-+ depends on COMMON_CLK_QCOM
-+ help
-+ Support for the Krait ACC and GCC clock controllers. Say Y
-+ if you want to support CPU frequency scaling on devices such
-+ as MSM8960, APQ8064, etc.
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -45,4 +45,5 @@ obj-$(CONFIG_SDM_DISPCC_845) += dispcc-s
- obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
- obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
- obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
-+obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
- obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
---- /dev/null
-+++ b/drivers/clk/qcom/kpss-xcc.c
-@@ -0,0 +1,87 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+
-+static const char *aux_parents[] = {
-+ "pll8_vote",
-+ "pxo",
-+};
-+
-+static unsigned int aux_parent_map[] = {
-+ 3,
-+ 0,
-+};
-+
-+static const struct of_device_id kpss_xcc_match_table[] = {
-+ { .compatible = "qcom,kpss-acc-v1", .data = (void *)1UL },
-+ { .compatible = "qcom,kpss-gcc" },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, kpss_xcc_match_table);
-+
-+static int kpss_xcc_driver_probe(struct platform_device *pdev)
-+{
-+ const struct of_device_id *id;
-+ struct clk *clk;
-+ struct resource *res;
-+ void __iomem *base;
-+ const char *name;
-+
-+ id = of_match_device(kpss_xcc_match_table, &pdev->dev);
-+ if (!id)
-+ return -ENODEV;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ base = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ if (id->data) {
-+ if (of_property_read_string_index(pdev->dev.of_node,
-+ "clock-output-names",
-+ 0, &name))
-+ return -ENODEV;
-+ base += 0x14;
-+ } else {
-+ name = "acpu_l2_aux";
-+ base += 0x28;
-+ }
-+
-+ clk = clk_register_mux_table(&pdev->dev, name, aux_parents,
-+ ARRAY_SIZE(aux_parents), 0, base, 0, 0x3,
-+ 0, aux_parent_map, NULL);
-+
-+ platform_set_drvdata(pdev, clk);
-+
-+ return PTR_ERR_OR_ZERO(clk);
-+}
-+
-+static int kpss_xcc_driver_remove(struct platform_device *pdev)
-+{
-+ clk_unregister_mux(platform_get_drvdata(pdev));
-+ return 0;
-+}
-+
-+static struct platform_driver kpss_xcc_driver = {
-+ .probe = kpss_xcc_driver_probe,
-+ .remove = kpss_xcc_driver_remove,
-+ .driver = {
-+ .name = "kpss-xcc",
-+ .of_match_table = kpss_xcc_match_table,
-+ },
-+};
-+module_platform_driver(kpss_xcc_driver);
-+
-+MODULE_DESCRIPTION("Krait Processor Sub System (KPSS) Clock Driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:kpss-xcc");
+++ /dev/null
-From 40e5ddf4f84869815129551f4a8cfc2c223ebeae Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:28 +0530
-Subject: [PATCH 09/12] dt-bindings: arm: Document qcom,kpss-gcc
-
-The ACC and GCC regions present in KPSSv1 contain registers to
-control clocks and power to each Krait CPU and L2. Documenting
-the bindings here.
-
-Reviewed-by: Rob Herring <robh@kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- .../bindings/arm/msm/qcom,kpss-acc.txt | 19 ++++++++
- .../bindings/arm/msm/qcom,kpss-gcc.txt | 44 +++++++++++++++++++
- 2 files changed, 63 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
-
---- a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt
-+++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt
-@@ -21,10 +21,29 @@ PROPERTIES
- the register region. An optional second element specifies
- the base address and size of the alias register region.
-
-+- clocks:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: reference to the pll parents.
-+
-+- clock-names:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: must be "pll8_vote", "pxo".
-+
-+- clock-output-names:
-+ Usage: optional
-+ Value type: <string>
-+ Definition: Name of the output clock. Typically acpuX_aux where X is a
-+ CPU number starting at 0.
-+
- Example:
-
- clock-controller@2088000 {
- compatible = "qcom,kpss-acc-v2";
- reg = <0x02088000 0x1000>,
- <0x02008000 0x1000>;
-+ clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>;
-+ clock-names = "pll8_vote", "pxo";
-+ clock-output-names = "acpu0_aux";
- };
---- /dev/null
-+++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
-@@ -0,0 +1,44 @@
-+Krait Processor Sub-system (KPSS) Global Clock Controller (GCC)
-+
-+PROPERTIES
-+
-+- compatible:
-+ Usage: required
-+ Value type: <string>
-+ Definition: should be one of the following. The generic compatible
-+ "qcom,kpss-gcc" should also be included.
-+ "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc"
-+ "qcom,kpss-gcc-apq8064", "qcom,kpss-gcc"
-+ "qcom,kpss-gcc-msm8974", "qcom,kpss-gcc"
-+ "qcom,kpss-gcc-msm8960", "qcom,kpss-gcc"
-+
-+- reg:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: base address and size of the register region
-+
-+- clocks:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: reference to the pll parents.
-+
-+- clock-names:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: must be "pll8_vote", "pxo".
-+
-+- clock-output-names:
-+ Usage: required
-+ Value type: <string>
-+ Definition: Name of the output clock. Typically acpu_l2_aux indicating
-+ an L2 cache auxiliary clock.
-+
-+Example:
-+
-+ l2cc: clock-controller@2011000 {
-+ compatible = "qcom,kpss-gcc-ipq8064", "qcom,kpss-gcc";
-+ reg = <0x2011000 0x1000>;
-+ clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>;
-+ clock-names = "pll8_vote", "pxo";
-+ clock-output-names = "acpu_l2_aux";
-+ };
+++ /dev/null
-From bb5c4a85051e5e0be39c775b6df85521f2ae807d Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:29 +0530
-Subject: [PATCH 10/12] clk: qcom: Add Krait clock controller driver
-
-The Krait CPU clocks are made up of a primary mux and secondary
-mux for each CPU and the L2, controlled via cp15 accessors. For
-Kraits within KPSSv1 each secondary mux accepts a different aux
-source, but on KPSSv2 each secondary mux accepts the same aux
-source.
-
-Cc: <devicetree@vger.kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/qcom/Kconfig | 8 +
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/clk-krait.c | 4 +-
- drivers/clk/qcom/krait-cc.c | 341 +++++++++++++++++++++++++++++++++++
- 4 files changed, 352 insertions(+), 2 deletions(-)
- create mode 100644 drivers/clk/qcom/krait-cc.c
-
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -292,3 +292,11 @@ config KPSS_XCC
- Support for the Krait ACC and GCC clock controllers. Say Y
- if you want to support CPU frequency scaling on devices such
- as MSM8960, APQ8064, etc.
-+
-+config KRAITCC
-+ tristate "Krait Clock Controller"
-+ depends on COMMON_CLK_QCOM && ARM
-+ select KRAIT_CLOCKS
-+ help
-+ Support for the Krait CPU clocks on Qualcomm devices.
-+ Say Y if you want to support CPU frequency scaling.
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -47,3 +47,4 @@ obj-$(CONFIG_SDM_VIDEOCC_845) += videocc
- obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
- obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
- obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
-+obj-$(CONFIG_KRAITCC) += krait-cc.o
---- a/drivers/clk/qcom/clk-krait.c
-+++ b/drivers/clk/qcom/clk-krait.c
-@@ -44,7 +44,7 @@ static int krait_mux_set_parent(struct c
- struct krait_mux_clk *mux = to_krait_mux_clk(hw);
- u32 sel;
-
-- sel = clk_mux_reindex(index, mux->parent_map, 0);
-+ sel = clk_mux_index_to_val(mux->parent_map, 0, index);
- mux->en_mask = sel;
- /* Don't touch mux if CPU is off as it won't work */
- if (__clk_is_enabled(hw->clk))
-@@ -63,7 +63,7 @@ static u8 krait_mux_get_parent(struct cl
- sel &= mux->mask;
- mux->en_mask = sel;
-
-- return clk_mux_get_parent(hw, sel, mux->parent_map, 0);
-+ return clk_mux_val_to_index(hw, mux->parent_map, 0, sel);
- }
-
- const struct clk_ops krait_mux_clk_ops = {
---- /dev/null
-+++ b/drivers/clk/qcom/krait-cc.c
-@@ -0,0 +1,341 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/slab.h>
-+
-+#include "clk-krait.h"
-+
-+static unsigned int sec_mux_map[] = {
-+ 2,
-+ 0,
-+};
-+
-+static unsigned int pri_mux_map[] = {
-+ 1,
-+ 2,
-+ 0,
-+};
-+
-+static int
-+krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
-+{
-+ struct krait_div2_clk *div;
-+ struct clk_init_data init = {
-+ .num_parents = 1,
-+ .ops = &krait_div2_clk_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ };
-+ const char *p_names[1];
-+ struct clk *clk;
-+
-+ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
-+ if (!div)
-+ return -ENOMEM;
-+
-+ div->width = 2;
-+ div->shift = 6;
-+ div->lpl = id >= 0;
-+ div->offset = offset;
-+ div->hw.init = &init;
-+
-+ init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
-+ if (!init.name)
-+ return -ENOMEM;
-+
-+ init.parent_names = p_names;
-+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
-+ if (!p_names[0]) {
-+ kfree(init.name);
-+ return -ENOMEM;
-+ }
-+
-+ clk = devm_clk_register(dev, &div->hw);
-+ kfree(p_names[0]);
-+ kfree(init.name);
-+
-+ return PTR_ERR_OR_ZERO(clk);
-+}
-+
-+static int
-+krait_add_sec_mux(struct device *dev, int id, const char *s,
-+ unsigned int offset, bool unique_aux)
-+{
-+ struct krait_mux_clk *mux;
-+ static const char *sec_mux_list[] = {
-+ "acpu_aux",
-+ "qsb",
-+ };
-+ struct clk_init_data init = {
-+ .parent_names = sec_mux_list,
-+ .num_parents = ARRAY_SIZE(sec_mux_list),
-+ .ops = &krait_mux_clk_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ };
-+ struct clk *clk;
-+
-+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
-+ if (!mux)
-+ return -ENOMEM;
-+
-+ mux->offset = offset;
-+ mux->lpl = id >= 0;
-+ mux->mask = 0x3;
-+ mux->shift = 2;
-+ mux->parent_map = sec_mux_map;
-+ mux->hw.init = &init;
-+
-+ init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
-+ if (!init.name)
-+ return -ENOMEM;
-+
-+ if (unique_aux) {
-+ sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s);
-+ if (!sec_mux_list[0]) {
-+ clk = ERR_PTR(-ENOMEM);
-+ goto err_aux;
-+ }
-+ }
-+
-+ clk = devm_clk_register(dev, &mux->hw);
-+
-+ if (unique_aux)
-+ kfree(sec_mux_list[0]);
-+err_aux:
-+ kfree(init.name);
-+ return PTR_ERR_OR_ZERO(clk);
-+}
-+
-+static struct clk *
-+krait_add_pri_mux(struct device *dev, int id, const char *s,
-+ unsigned int offset)
-+{
-+ struct krait_mux_clk *mux;
-+ const char *p_names[3];
-+ struct clk_init_data init = {
-+ .parent_names = p_names,
-+ .num_parents = ARRAY_SIZE(p_names),
-+ .ops = &krait_mux_clk_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ };
-+ struct clk *clk;
-+
-+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
-+ if (!mux)
-+ return ERR_PTR(-ENOMEM);
-+
-+ mux->mask = 0x3;
-+ mux->shift = 0;
-+ mux->offset = offset;
-+ mux->lpl = id >= 0;
-+ mux->parent_map = pri_mux_map;
-+ mux->hw.init = &init;
-+
-+ init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
-+ if (!init.name)
-+ return ERR_PTR(-ENOMEM);
-+
-+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
-+ if (!p_names[0]) {
-+ clk = ERR_PTR(-ENOMEM);
-+ goto err_p0;
-+ }
-+
-+ p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
-+ if (!p_names[1]) {
-+ clk = ERR_PTR(-ENOMEM);
-+ goto err_p1;
-+ }
-+
-+ p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
-+ if (!p_names[2]) {
-+ clk = ERR_PTR(-ENOMEM);
-+ goto err_p2;
-+ }
-+
-+ clk = devm_clk_register(dev, &mux->hw);
-+
-+ kfree(p_names[2]);
-+err_p2:
-+ kfree(p_names[1]);
-+err_p1:
-+ kfree(p_names[0]);
-+err_p0:
-+ kfree(init.name);
-+ return clk;
-+}
-+
-+/* id < 0 for L2, otherwise id == physical CPU number */
-+static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux)
-+{
-+ int ret;
-+ unsigned int offset;
-+ void *p = NULL;
-+ const char *s;
-+ struct clk *clk;
-+
-+ if (id >= 0) {
-+ offset = 0x4501 + (0x1000 * id);
-+ s = p = kasprintf(GFP_KERNEL, "%d", id);
-+ if (!s)
-+ return ERR_PTR(-ENOMEM);
-+ } else {
-+ offset = 0x500;
-+ s = "_l2";
-+ }
-+
-+ ret = krait_add_div(dev, id, s, offset);
-+ if (ret) {
-+ clk = ERR_PTR(ret);
-+ goto err;
-+ }
-+
-+ ret = krait_add_sec_mux(dev, id, s, offset, unique_aux);
-+ if (ret) {
-+ clk = ERR_PTR(ret);
-+ goto err;
-+ }
-+
-+ clk = krait_add_pri_mux(dev, id, s, offset);
-+err:
-+ kfree(p);
-+ return clk;
-+}
-+
-+static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data)
-+{
-+ unsigned int idx = clkspec->args[0];
-+ struct clk **clks = data;
-+
-+ if (idx >= 5) {
-+ pr_err("%s: invalid clock index %d\n", __func__, idx);
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ return clks[idx] ? : ERR_PTR(-ENODEV);
-+}
-+
-+static const struct of_device_id krait_cc_match_table[] = {
-+ { .compatible = "qcom,krait-cc-v1", (void *)1UL },
-+ { .compatible = "qcom,krait-cc-v2" },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, krait_cc_match_table);
-+
-+static int krait_cc_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ const struct of_device_id *id;
-+ unsigned long cur_rate, aux_rate;
-+ int cpu;
-+ struct clk *clk;
-+ struct clk **clks;
-+ struct clk *l2_pri_mux_clk;
-+
-+ id = of_match_device(krait_cc_match_table, dev);
-+ if (!id)
-+ return -ENODEV;
-+
-+ /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */
-+ clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1);
-+ if (IS_ERR(clk))
-+ return PTR_ERR(clk);
-+
-+ if (!id->data) {
-+ clk = clk_register_fixed_factor(dev, "acpu_aux",
-+ "gpll0_vote", 0, 1, 2);
-+ if (IS_ERR(clk))
-+ return PTR_ERR(clk);
-+ }
-+
-+ /* Krait configurations have at most 4 CPUs and one L2 */
-+ clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL);
-+ if (!clks)
-+ return -ENOMEM;
-+
-+ for_each_possible_cpu(cpu) {
-+ clk = krait_add_clks(dev, cpu, id->data);
-+ if (IS_ERR(clk))
-+ return PTR_ERR(clk);
-+ clks[cpu] = clk;
-+ }
-+
-+ l2_pri_mux_clk = krait_add_clks(dev, -1, id->data);
-+ if (IS_ERR(l2_pri_mux_clk))
-+ return PTR_ERR(l2_pri_mux_clk);
-+ clks[4] = l2_pri_mux_clk;
-+
-+ /*
-+ * We don't want the CPU or L2 clocks to be turned off at late init
-+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
-+ * refcount of these clocks. Any cpufreq/hotplug manager can assume
-+ * that the clocks have already been prepared and enabled by the time
-+ * they take over.
-+ */
-+ for_each_online_cpu(cpu) {
-+ clk_prepare_enable(l2_pri_mux_clk);
-+ WARN(clk_prepare_enable(clks[cpu]),
-+ "Unable to turn on CPU%d clock", cpu);
-+ }
-+
-+ /*
-+ * Force reinit of HFPLLs and muxes to overwrite any potential
-+ * incorrect configuration of HFPLLs and muxes by the bootloader.
-+ * While at it, also make sure the cores are running at known rates
-+ * and print the current rate.
-+ *
-+ * The clocks are set to aux clock rate first to make sure the
-+ * secondary mux is not sourcing off of QSB. The rate is then set to
-+ * two different rates to force a HFPLL reinit under all
-+ * circumstances.
-+ */
-+ cur_rate = clk_get_rate(l2_pri_mux_clk);
-+ aux_rate = 384000000;
-+ if (cur_rate == 1) {
-+ pr_info("L2 @ QSB rate. Forcing new rate.\n");
-+ cur_rate = aux_rate;
-+ }
-+ clk_set_rate(l2_pri_mux_clk, aux_rate);
-+ clk_set_rate(l2_pri_mux_clk, 2);
-+ clk_set_rate(l2_pri_mux_clk, cur_rate);
-+ pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000);
-+ for_each_possible_cpu(cpu) {
-+ clk = clks[cpu];
-+ cur_rate = clk_get_rate(clk);
-+ if (cur_rate == 1) {
-+ pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu);
-+ cur_rate = aux_rate;
-+ }
-+
-+ clk_set_rate(clk, aux_rate);
-+ clk_set_rate(clk, 2);
-+ clk_set_rate(clk, cur_rate);
-+ pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000);
-+ }
-+
-+ of_clk_add_provider(dev->of_node, krait_of_get, clks);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver krait_cc_driver = {
-+ .probe = krait_cc_probe,
-+ .driver = {
-+ .name = "krait-cc",
-+ .of_match_table = krait_cc_match_table,
-+ },
-+};
-+module_platform_driver(krait_cc_driver);
-+
-+MODULE_DESCRIPTION("Krait CPU Clock Driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:krait-cc");
+++ /dev/null
-From bf4503ccf321811192cb07f9711556237c3cf668 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:30 +0530
-Subject: [PATCH 11/12] dt-bindings: clock: Document qcom,krait-cc
-
-The Krait clock controller controls the krait CPU and the L2 clocks
-consisting a primary mux and secondary mux. Add document for that.
-
-Reviewed-by: Rob Herring <robh@kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- .../bindings/clock/qcom,krait-cc.txt | 34 +++++++++++++++++++
- 1 file changed, 34 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
-@@ -0,0 +1,34 @@
-+Krait Clock Controller
-+
-+PROPERTIES
-+
-+- compatible:
-+ Usage: required
-+ Value type: <string>
-+ Definition: must be one of:
-+ "qcom,krait-cc-v1"
-+ "qcom,krait-cc-v2"
-+
-+- #clock-cells:
-+ Usage: required
-+ Value type: <u32>
-+ Definition: must be 1
-+
-+- clocks:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: reference to the clock parents of hfpll, secondary muxes.
-+
-+- clock-names:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: must be "hfpll0", "hfpll1", "acpu0_aux", "acpu1_aux", "qsb".
-+
-+Example:
-+
-+ kraitcc: clock-controller {
-+ compatible = "qcom,krait-cc-v1";
-+ clocks = <&hfpll0>, <&hfpll1>, <&acpu0_aux>, <&acpu1_aux>, <qsb>;
-+ clock-names = "hfpll0", "hfpll1", "acpu0_aux", "acpu1_aux", "qsb";
-+ #clock-cells = <1>;
-+ };
+++ /dev/null
-From 77612720a2362230af726baa4149c40ec7a7fb05 Mon Sep 17 00:00:00 2001
-From: Sricharan R <sricharan@codeaurora.org>
-Date: Tue, 14 Aug 2018 17:42:31 +0530
-Subject: [PATCH 12/12] clk: qcom: Add safe switch hook for krait mux clocks
-
-When the Hfplls are reprogrammed during the rate change,
-the primary muxes which are sourced from the same hfpll
-for higher frequencies, needs to be switched to the 'safe
-secondary mux' as the parent for that small window. This
-is done by registering a clk notifier for the muxes and
-switching to the safe parent in the PRE_RATE_CHANGE notifier
-and back to the original parent in the POST_RATE_CHANGE notifier.
-
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-Tested-by: Craig Tatlor <ctatlor97@gmail.com>
-Signed-off-by: Stephen Boyd <sboyd@kernel.org>
----
- drivers/clk/qcom/clk-krait.c | 2 ++
- drivers/clk/qcom/clk-krait.h | 3 ++
- drivers/clk/qcom/krait-cc.c | 56 ++++++++++++++++++++++++++++++++++++
- 3 files changed, 61 insertions(+)
-
---- a/drivers/clk/qcom/clk-krait.c
-+++ b/drivers/clk/qcom/clk-krait.c
-@@ -50,6 +50,8 @@ static int krait_mux_set_parent(struct c
- if (__clk_is_enabled(hw->clk))
- __krait_mux_set_sel(mux, sel);
-
-+ mux->reparent = true;
-+
- return 0;
- }
-
---- a/drivers/clk/qcom/clk-krait.h
-+++ b/drivers/clk/qcom/clk-krait.h
-@@ -12,6 +12,9 @@ struct krait_mux_clk {
- u32 shift;
- u32 en_mask;
- bool lpl;
-+ u8 safe_sel;
-+ u8 old_index;
-+ bool reparent;
-
- struct clk_hw hw;
- struct notifier_block clk_nb;
---- a/drivers/clk/qcom/krait-cc.c
-+++ b/drivers/clk/qcom/krait-cc.c
-@@ -26,6 +26,49 @@ static unsigned int pri_mux_map[] = {
- 0,
- };
-
-+/*
-+ * Notifier function for switching the muxes to safe parent
-+ * while the hfpll is getting reprogrammed.
-+ */
-+static int krait_notifier_cb(struct notifier_block *nb,
-+ unsigned long event,
-+ void *data)
-+{
-+ int ret = 0;
-+ struct krait_mux_clk *mux = container_of(nb, struct krait_mux_clk,
-+ clk_nb);
-+ /* Switch to safe parent */
-+ if (event == PRE_RATE_CHANGE) {
-+ mux->old_index = krait_mux_clk_ops.get_parent(&mux->hw);
-+ ret = krait_mux_clk_ops.set_parent(&mux->hw, mux->safe_sel);
-+ mux->reparent = false;
-+ /*
-+ * By the time POST_RATE_CHANGE notifier is called,
-+ * clk framework itself would have changed the parent for the new rate.
-+ * Only otherwise, put back to the old parent.
-+ */
-+ } else if (event == POST_RATE_CHANGE) {
-+ if (!mux->reparent)
-+ ret = krait_mux_clk_ops.set_parent(&mux->hw,
-+ mux->old_index);
-+ }
-+
-+ return notifier_from_errno(ret);
-+}
-+
-+static int krait_notifier_register(struct device *dev, struct clk *clk,
-+ struct krait_mux_clk *mux)
-+{
-+ int ret = 0;
-+
-+ mux->clk_nb.notifier_call = krait_notifier_cb;
-+ ret = clk_notifier_register(clk, &mux->clk_nb);
-+ if (ret)
-+ dev_err(dev, "failed to register clock notifier: %d\n", ret);
-+
-+ return ret;
-+}
-+
- static int
- krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
- {
-@@ -70,6 +113,7 @@ static int
- krait_add_sec_mux(struct device *dev, int id, const char *s,
- unsigned int offset, bool unique_aux)
- {
-+ int ret;
- struct krait_mux_clk *mux;
- static const char *sec_mux_list[] = {
- "acpu_aux",
-@@ -93,6 +137,7 @@ krait_add_sec_mux(struct device *dev, in
- mux->shift = 2;
- mux->parent_map = sec_mux_map;
- mux->hw.init = &init;
-+ mux->safe_sel = 0;
-
- init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
- if (!init.name)
-@@ -108,6 +153,11 @@ krait_add_sec_mux(struct device *dev, in
-
- clk = devm_clk_register(dev, &mux->hw);
-
-+ ret = krait_notifier_register(dev, clk, mux);
-+ if (ret)
-+ goto unique_aux;
-+
-+unique_aux:
- if (unique_aux)
- kfree(sec_mux_list[0]);
- err_aux:
-@@ -119,6 +169,7 @@ static struct clk *
- krait_add_pri_mux(struct device *dev, int id, const char *s,
- unsigned int offset)
- {
-+ int ret;
- struct krait_mux_clk *mux;
- const char *p_names[3];
- struct clk_init_data init = {
-@@ -139,6 +190,7 @@ krait_add_pri_mux(struct device *dev, in
- mux->lpl = id >= 0;
- mux->parent_map = pri_mux_map;
- mux->hw.init = &init;
-+ mux->safe_sel = 2;
-
- init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
- if (!init.name)
-@@ -164,6 +216,10 @@ krait_add_pri_mux(struct device *dev, in
-
- clk = devm_clk_register(dev, &mux->hw);
-
-+ ret = krait_notifier_register(dev, clk, mux);
-+ if (ret)
-+ goto err_p3;
-+err_p3:
- kfree(p_names[2]);
- err_p2:
- kfree(p_names[1]);
+++ /dev/null
-From 50c0b12f098fb3cfac7abcc0f2b5409f6bac5fa2 Mon Sep 17 00:00:00 2001
-From: Yangtao Li <tiny.windzz@gmail.com>
-Date: Mon, 4 Feb 2019 01:13:10 -0500
-Subject: [PATCH] cpufreq: qcom-kryo: make some variables static
-
-The variables are local to the source and do not
-need to be in global scope, so make them static.
-
-Signed-off-by: Yangtao Li <tiny.windzz@gmail.com>
-Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
----
- drivers/cpufreq/qcom-cpufreq-kryo.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/cpufreq/qcom-cpufreq-kryo.c
-+++ b/drivers/cpufreq/qcom-cpufreq-kryo.c
-@@ -42,7 +42,7 @@ enum _msm8996_version {
- NUM_OF_MSM8996_VERSIONS,
- };
-
--struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev;
-+static struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev;
-
- static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void)
- {
+++ /dev/null
-From 7d12709544b8b3fb9727a34a664b8380e1e3493a Mon Sep 17 00:00:00 2001
-From: Sricharan R <sricharan@codeaurora.org>
-Date: Thu, 25 Jul 2019 12:41:31 +0200
-Subject: [PATCH] cpufreq: qcom: Re-organise kryo cpufreq to use it for other
- nvmem based qcom socs
-
-The kryo cpufreq driver reads the nvmem cell and uses that data to
-populate the opps. There are other qcom cpufreq socs like krait which
-does similar thing. Except for the interpretation of the read data,
-rest of the driver is same for both the cases. So pull the common things
-out for reuse.
-
-Signed-off-by: Sricharan R <sricharan@codeaurora.org>
-[niklas.cassel@linaro.org: split dt-binding into a separate patch and
-do not rename the compatible string. Update MAINTAINERS file.]
-Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
-Reviewed-by: Ilia Lin <ilia.lin@kernel.org>
-Reviewed-by: Stephen Boyd <sboyd@kernel.org>
-Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
----
- MAINTAINERS | 4 +-
- drivers/cpufreq/Kconfig.arm | 4 +-
- drivers/cpufreq/Makefile | 2 +-
- ...om-cpufreq-kryo.c => qcom-cpufreq-nvmem.c} | 122 +++++++++++-------
- 4 files changed, 78 insertions(+), 54 deletions(-)
- rename drivers/cpufreq/{qcom-cpufreq-kryo.c => qcom-cpufreq-nvmem.c} (69%)
-
---- a/drivers/cpufreq/Kconfig.arm
-+++ b/drivers/cpufreq/Kconfig.arm
-@@ -110,8 +110,8 @@ config ARM_OMAP2PLUS_CPUFREQ
- depends on ARCH_OMAP2PLUS
- default ARCH_OMAP2PLUS
-
--config ARM_QCOM_CPUFREQ_KRYO
-- tristate "Qualcomm Kryo based CPUFreq"
-+config ARM_QCOM_CPUFREQ_NVMEM
-+ tristate "Qualcomm nvmem based CPUFreq"
- depends on ARM64
- depends on QCOM_QFPROM
- depends on QCOM_SMEM
---- a/drivers/cpufreq/Makefile
-+++ b/drivers/cpufreq/Makefile
-@@ -64,7 +64,7 @@ obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cp
- obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
- obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
- obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
--obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o
-+obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o
- obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
- obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
- obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
---- a/drivers/cpufreq/qcom-cpufreq-kryo.c
-+++ /dev/null
-@@ -1,249 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0
--/*
-- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
-- */
--
--/*
-- * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors,
-- * the CPU frequency subset and voltage value of each OPP varies
-- * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables
-- * defines the voltage and frequency value based on the msm-id in SMEM
-- * and speedbin blown in the efuse combination.
-- * The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC
-- * to provide the OPP framework with required information.
-- * This is used to determine the voltage and frequency value for each OPP of
-- * operating-points-v2 table when it is parsed by the OPP framework.
-- */
--
--#include <linux/cpu.h>
--#include <linux/err.h>
--#include <linux/init.h>
--#include <linux/kernel.h>
--#include <linux/module.h>
--#include <linux/nvmem-consumer.h>
--#include <linux/of.h>
--#include <linux/platform_device.h>
--#include <linux/pm_opp.h>
--#include <linux/slab.h>
--#include <linux/soc/qcom/smem.h>
--
--#define MSM_ID_SMEM 137
--
--enum _msm_id {
-- MSM8996V3 = 0xF6ul,
-- APQ8096V3 = 0x123ul,
-- MSM8996SG = 0x131ul,
-- APQ8096SG = 0x138ul,
--};
--
--enum _msm8996_version {
-- MSM8996_V3,
-- MSM8996_SG,
-- NUM_OF_MSM8996_VERSIONS,
--};
--
--static struct platform_device *cpufreq_dt_pdev, *kryo_cpufreq_pdev;
--
--static enum _msm8996_version qcom_cpufreq_kryo_get_msm_id(void)
--{
-- size_t len;
-- u32 *msm_id;
-- enum _msm8996_version version;
--
-- msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len);
-- if (IS_ERR(msm_id))
-- return NUM_OF_MSM8996_VERSIONS;
--
-- /* The first 4 bytes are format, next to them is the actual msm-id */
-- msm_id++;
--
-- switch ((enum _msm_id)*msm_id) {
-- case MSM8996V3:
-- case APQ8096V3:
-- version = MSM8996_V3;
-- break;
-- case MSM8996SG:
-- case APQ8096SG:
-- version = MSM8996_SG;
-- break;
-- default:
-- version = NUM_OF_MSM8996_VERSIONS;
-- }
--
-- return version;
--}
--
--static int qcom_cpufreq_kryo_probe(struct platform_device *pdev)
--{
-- struct opp_table **opp_tables;
-- enum _msm8996_version msm8996_version;
-- struct nvmem_cell *speedbin_nvmem;
-- struct device_node *np;
-- struct device *cpu_dev;
-- unsigned cpu;
-- u8 *speedbin;
-- u32 versions;
-- size_t len;
-- int ret;
--
-- cpu_dev = get_cpu_device(0);
-- if (!cpu_dev)
-- return -ENODEV;
--
-- msm8996_version = qcom_cpufreq_kryo_get_msm_id();
-- if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
-- dev_err(cpu_dev, "Not Snapdragon 820/821!");
-- return -ENODEV;
-- }
--
-- np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
-- if (!np)
-- return -ENOENT;
--
-- ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
-- if (!ret) {
-- of_node_put(np);
-- return -ENOENT;
-- }
--
-- speedbin_nvmem = of_nvmem_cell_get(np, NULL);
-- of_node_put(np);
-- if (IS_ERR(speedbin_nvmem)) {
-- if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER)
-- dev_err(cpu_dev, "Could not get nvmem cell: %ld\n",
-- PTR_ERR(speedbin_nvmem));
-- return PTR_ERR(speedbin_nvmem);
-- }
--
-- speedbin = nvmem_cell_read(speedbin_nvmem, &len);
-- nvmem_cell_put(speedbin_nvmem);
-- if (IS_ERR(speedbin))
-- return PTR_ERR(speedbin);
--
-- switch (msm8996_version) {
-- case MSM8996_V3:
-- versions = 1 << (unsigned int)(*speedbin);
-- break;
-- case MSM8996_SG:
-- versions = 1 << ((unsigned int)(*speedbin) + 4);
-- break;
-- default:
-- BUG();
-- break;
-- }
-- kfree(speedbin);
--
-- opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables), GFP_KERNEL);
-- if (!opp_tables)
-- return -ENOMEM;
--
-- for_each_possible_cpu(cpu) {
-- cpu_dev = get_cpu_device(cpu);
-- if (NULL == cpu_dev) {
-- ret = -ENODEV;
-- goto free_opp;
-- }
--
-- opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev,
-- &versions, 1);
-- if (IS_ERR(opp_tables[cpu])) {
-- ret = PTR_ERR(opp_tables[cpu]);
-- dev_err(cpu_dev, "Failed to set supported hardware\n");
-- goto free_opp;
-- }
-- }
--
-- cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
-- NULL, 0);
-- if (!IS_ERR(cpufreq_dt_pdev)) {
-- platform_set_drvdata(pdev, opp_tables);
-- return 0;
-- }
--
-- ret = PTR_ERR(cpufreq_dt_pdev);
-- dev_err(cpu_dev, "Failed to register platform device\n");
--
--free_opp:
-- for_each_possible_cpu(cpu) {
-- if (IS_ERR_OR_NULL(opp_tables[cpu]))
-- break;
-- dev_pm_opp_put_supported_hw(opp_tables[cpu]);
-- }
-- kfree(opp_tables);
--
-- return ret;
--}
--
--static int qcom_cpufreq_kryo_remove(struct platform_device *pdev)
--{
-- struct opp_table **opp_tables = platform_get_drvdata(pdev);
-- unsigned int cpu;
--
-- platform_device_unregister(cpufreq_dt_pdev);
--
-- for_each_possible_cpu(cpu)
-- dev_pm_opp_put_supported_hw(opp_tables[cpu]);
--
-- kfree(opp_tables);
--
-- return 0;
--}
--
--static struct platform_driver qcom_cpufreq_kryo_driver = {
-- .probe = qcom_cpufreq_kryo_probe,
-- .remove = qcom_cpufreq_kryo_remove,
-- .driver = {
-- .name = "qcom-cpufreq-kryo",
-- },
--};
--
--static const struct of_device_id qcom_cpufreq_kryo_match_list[] __initconst = {
-- { .compatible = "qcom,apq8096", },
-- { .compatible = "qcom,msm8996", },
-- {}
--};
--
--/*
-- * Since the driver depends on smem and nvmem drivers, which may
-- * return EPROBE_DEFER, all the real activity is done in the probe,
-- * which may be defered as well. The init here is only registering
-- * the driver and the platform device.
-- */
--static int __init qcom_cpufreq_kryo_init(void)
--{
-- struct device_node *np = of_find_node_by_path("/");
-- const struct of_device_id *match;
-- int ret;
--
-- if (!np)
-- return -ENODEV;
--
-- match = of_match_node(qcom_cpufreq_kryo_match_list, np);
-- of_node_put(np);
-- if (!match)
-- return -ENODEV;
--
-- ret = platform_driver_register(&qcom_cpufreq_kryo_driver);
-- if (unlikely(ret < 0))
-- return ret;
--
-- kryo_cpufreq_pdev = platform_device_register_simple(
-- "qcom-cpufreq-kryo", -1, NULL, 0);
-- ret = PTR_ERR_OR_ZERO(kryo_cpufreq_pdev);
-- if (0 == ret)
-- return 0;
--
-- platform_driver_unregister(&qcom_cpufreq_kryo_driver);
-- return ret;
--}
--module_init(qcom_cpufreq_kryo_init);
--
--static void __exit qcom_cpufreq_kryo_exit(void)
--{
-- platform_device_unregister(kryo_cpufreq_pdev);
-- platform_driver_unregister(&qcom_cpufreq_kryo_driver);
--}
--module_exit(qcom_cpufreq_kryo_exit);
--
--MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Kryo CPUfreq driver");
--MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
-@@ -0,0 +1,273 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
-+ */
-+
-+/*
-+ * In Certain QCOM SoCs like apq8096 and msm8996 that have KRYO processors,
-+ * the CPU frequency subset and voltage value of each OPP varies
-+ * based on the silicon variant in use. Qualcomm Process Voltage Scaling Tables
-+ * defines the voltage and frequency value based on the msm-id in SMEM
-+ * and speedbin blown in the efuse combination.
-+ * The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC
-+ * to provide the OPP framework with required information.
-+ * This is used to determine the voltage and frequency value for each OPP of
-+ * operating-points-v2 table when it is parsed by the OPP framework.
-+ */
-+
-+#include <linux/cpu.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/nvmem-consumer.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_opp.h>
-+#include <linux/slab.h>
-+#include <linux/soc/qcom/smem.h>
-+
-+#define MSM_ID_SMEM 137
-+
-+enum _msm_id {
-+ MSM8996V3 = 0xF6ul,
-+ APQ8096V3 = 0x123ul,
-+ MSM8996SG = 0x131ul,
-+ APQ8096SG = 0x138ul,
-+};
-+
-+enum _msm8996_version {
-+ MSM8996_V3,
-+ MSM8996_SG,
-+ NUM_OF_MSM8996_VERSIONS,
-+};
-+
-+static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
-+
-+static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
-+{
-+ size_t len;
-+ u32 *msm_id;
-+ enum _msm8996_version version;
-+
-+ msm_id = qcom_smem_get(QCOM_SMEM_HOST_ANY, MSM_ID_SMEM, &len);
-+ if (IS_ERR(msm_id))
-+ return NUM_OF_MSM8996_VERSIONS;
-+
-+ /* The first 4 bytes are format, next to them is the actual msm-id */
-+ msm_id++;
-+
-+ switch ((enum _msm_id)*msm_id) {
-+ case MSM8996V3:
-+ case APQ8096V3:
-+ version = MSM8996_V3;
-+ break;
-+ case MSM8996SG:
-+ case APQ8096SG:
-+ version = MSM8996_SG;
-+ break;
-+ default:
-+ version = NUM_OF_MSM8996_VERSIONS;
-+ }
-+
-+ return version;
-+}
-+
-+static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
-+ struct nvmem_cell *speedbin_nvmem,
-+ u32 *versions)
-+{
-+ size_t len;
-+ u8 *speedbin;
-+ enum _msm8996_version msm8996_version;
-+
-+ msm8996_version = qcom_cpufreq_get_msm_id();
-+ if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
-+ dev_err(cpu_dev, "Not Snapdragon 820/821!");
-+ return -ENODEV;
-+ }
-+
-+ speedbin = nvmem_cell_read(speedbin_nvmem, &len);
-+ if (IS_ERR(speedbin))
-+ return PTR_ERR(speedbin);
-+
-+ switch (msm8996_version) {
-+ case MSM8996_V3:
-+ *versions = 1 << (unsigned int)(*speedbin);
-+ break;
-+ case MSM8996_SG:
-+ *versions = 1 << ((unsigned int)(*speedbin) + 4);
-+ break;
-+ default:
-+ BUG();
-+ break;
-+ }
-+
-+ kfree(speedbin);
-+ return 0;
-+}
-+
-+static int qcom_cpufreq_probe(struct platform_device *pdev)
-+{
-+ struct opp_table **opp_tables;
-+ int (*get_version)(struct device *cpu_dev,
-+ struct nvmem_cell *speedbin_nvmem,
-+ u32 *versions);
-+ struct nvmem_cell *speedbin_nvmem;
-+ struct device_node *np;
-+ struct device *cpu_dev;
-+ unsigned cpu;
-+ u32 versions;
-+ const struct of_device_id *match;
-+ int ret;
-+
-+ cpu_dev = get_cpu_device(0);
-+ if (!cpu_dev)
-+ return -ENODEV;
-+
-+ match = pdev->dev.platform_data;
-+ get_version = match->data;
-+ if (!get_version)
-+ return -ENODEV;
-+
-+ np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
-+ if (!np)
-+ return -ENOENT;
-+
-+ ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
-+ if (!ret) {
-+ of_node_put(np);
-+ return -ENOENT;
-+ }
-+
-+ speedbin_nvmem = of_nvmem_cell_get(np, NULL);
-+ of_node_put(np);
-+ if (IS_ERR(speedbin_nvmem)) {
-+ if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER)
-+ dev_err(cpu_dev, "Could not get nvmem cell: %ld\n",
-+ PTR_ERR(speedbin_nvmem));
-+ return PTR_ERR(speedbin_nvmem);
-+ }
-+
-+ ret = get_version(cpu_dev, speedbin_nvmem, &versions);
-+ nvmem_cell_put(speedbin_nvmem);
-+ if (ret)
-+ return ret;
-+
-+ opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables), GFP_KERNEL);
-+ if (!opp_tables)
-+ return -ENOMEM;
-+
-+ for_each_possible_cpu(cpu) {
-+ cpu_dev = get_cpu_device(cpu);
-+ if (NULL == cpu_dev) {
-+ ret = -ENODEV;
-+ goto free_opp;
-+ }
-+
-+ opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev,
-+ &versions, 1);
-+ if (IS_ERR(opp_tables[cpu])) {
-+ ret = PTR_ERR(opp_tables[cpu]);
-+ dev_err(cpu_dev, "Failed to set supported hardware\n");
-+ goto free_opp;
-+ }
-+ }
-+
-+ cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
-+ NULL, 0);
-+ if (!IS_ERR(cpufreq_dt_pdev)) {
-+ platform_set_drvdata(pdev, opp_tables);
-+ return 0;
-+ }
-+
-+ ret = PTR_ERR(cpufreq_dt_pdev);
-+ dev_err(cpu_dev, "Failed to register platform device\n");
-+
-+free_opp:
-+ for_each_possible_cpu(cpu) {
-+ if (IS_ERR_OR_NULL(opp_tables[cpu]))
-+ break;
-+ dev_pm_opp_put_supported_hw(opp_tables[cpu]);
-+ }
-+ kfree(opp_tables);
-+
-+ return ret;
-+}
-+
-+static int qcom_cpufreq_remove(struct platform_device *pdev)
-+{
-+ struct opp_table **opp_tables = platform_get_drvdata(pdev);
-+ unsigned int cpu;
-+
-+ platform_device_unregister(cpufreq_dt_pdev);
-+
-+ for_each_possible_cpu(cpu)
-+ dev_pm_opp_put_supported_hw(opp_tables[cpu]);
-+
-+ kfree(opp_tables);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver qcom_cpufreq_driver = {
-+ .probe = qcom_cpufreq_probe,
-+ .remove = qcom_cpufreq_remove,
-+ .driver = {
-+ .name = "qcom-cpufreq-nvmem",
-+ },
-+};
-+
-+static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
-+ { .compatible = "qcom,apq8096",
-+ .data = qcom_cpufreq_kryo_name_version },
-+ { .compatible = "qcom,msm8996",
-+ .data = qcom_cpufreq_kryo_name_version },
-+ {},
-+};
-+
-+/*
-+ * Since the driver depends on smem and nvmem drivers, which may
-+ * return EPROBE_DEFER, all the real activity is done in the probe,
-+ * which may be defered as well. The init here is only registering
-+ * the driver and the platform device.
-+ */
-+static int __init qcom_cpufreq_init(void)
-+{
-+ struct device_node *np = of_find_node_by_path("/");
-+ const struct of_device_id *match;
-+ int ret;
-+
-+ if (!np)
-+ return -ENODEV;
-+
-+ match = of_match_node(qcom_cpufreq_match_list, np);
-+ of_node_put(np);
-+ if (!match)
-+ return -ENODEV;
-+
-+ ret = platform_driver_register(&qcom_cpufreq_driver);
-+ if (unlikely(ret < 0))
-+ return ret;
-+
-+ cpufreq_pdev = platform_device_register_data(NULL, "qcom-cpufreq-nvmem",
-+ -1, match, sizeof(*match));
-+ ret = PTR_ERR_OR_ZERO(cpufreq_pdev);
-+ if (0 == ret)
-+ return 0;
-+
-+ platform_driver_unregister(&qcom_cpufreq_driver);
-+ return ret;
-+}
-+module_init(qcom_cpufreq_init);
-+
-+static void __exit qcom_cpufreq_exit(void)
-+{
-+ platform_device_unregister(cpufreq_pdev);
-+ platform_driver_unregister(&qcom_cpufreq_driver);
-+}
-+module_exit(qcom_cpufreq_exit);
-+
-+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. CPUfreq driver");
-+MODULE_LICENSE("GPL v2");
+++ /dev/null
-From 57f2f8b4aa0c6b41a284da82bfa40dc3b2abe9a5 Mon Sep 17 00:00:00 2001
-From: Niklas Cassel <niklas.cassel@linaro.org>
-Date: Thu, 25 Jul 2019 12:41:33 +0200
-Subject: [PATCH] cpufreq: qcom: Refactor the driver to make it easier to
- extend
-
-Refactor the driver to make it easier to extend in a later commit.
-
-Create a driver struct to collect all common resources, in order to make
-it easier to free up all common resources.
-Create a driver match_data struct to make it easier to extend the driver
-with support for new features that might only be supported on certain SoCs.
-
-Co-developed-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
-Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
-Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
-Reviewed-by: Ilia Lin <ilia.lin@kernel.org>
-Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
----
- drivers/cpufreq/qcom-cpufreq-nvmem.c | 123 +++++++++++++++++----------
- 1 file changed, 79 insertions(+), 44 deletions(-)
-
---- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
-+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
-@@ -43,6 +43,20 @@ enum _msm8996_version {
- NUM_OF_MSM8996_VERSIONS,
- };
-
-+struct qcom_cpufreq_drv;
-+
-+struct qcom_cpufreq_match_data {
-+ int (*get_version)(struct device *cpu_dev,
-+ struct nvmem_cell *speedbin_nvmem,
-+ struct qcom_cpufreq_drv *drv);
-+};
-+
-+struct qcom_cpufreq_drv {
-+ struct opp_table **opp_tables;
-+ u32 versions;
-+ const struct qcom_cpufreq_match_data *data;
-+};
-+
- static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
-
- static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
-@@ -76,7 +90,7 @@ static enum _msm8996_version qcom_cpufre
-
- static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
- struct nvmem_cell *speedbin_nvmem,
-- u32 *versions)
-+ struct qcom_cpufreq_drv *drv)
- {
- size_t len;
- u8 *speedbin;
-@@ -94,10 +108,10 @@ static int qcom_cpufreq_kryo_name_versio
-
- switch (msm8996_version) {
- case MSM8996_V3:
-- *versions = 1 << (unsigned int)(*speedbin);
-+ drv->versions = 1 << (unsigned int)(*speedbin);
- break;
- case MSM8996_SG:
-- *versions = 1 << ((unsigned int)(*speedbin) + 4);
-+ drv->versions = 1 << ((unsigned int)(*speedbin) + 4);
- break;
- default:
- BUG();
-@@ -108,17 +122,17 @@ static int qcom_cpufreq_kryo_name_versio
- return 0;
- }
-
-+static const struct qcom_cpufreq_match_data match_data_kryo = {
-+ .get_version = qcom_cpufreq_kryo_name_version,
-+};
-+
- static int qcom_cpufreq_probe(struct platform_device *pdev)
- {
-- struct opp_table **opp_tables;
-- int (*get_version)(struct device *cpu_dev,
-- struct nvmem_cell *speedbin_nvmem,
-- u32 *versions);
-+ struct qcom_cpufreq_drv *drv;
- struct nvmem_cell *speedbin_nvmem;
- struct device_node *np;
- struct device *cpu_dev;
- unsigned cpu;
-- u32 versions;
- const struct of_device_id *match;
- int ret;
-
-@@ -126,11 +140,6 @@ static int qcom_cpufreq_probe(struct pla
- if (!cpu_dev)
- return -ENODEV;
-
-- match = pdev->dev.platform_data;
-- get_version = match->data;
-- if (!get_version)
-- return -ENODEV;
--
- np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
- if (!np)
- return -ENOENT;
-@@ -141,23 +150,43 @@ static int qcom_cpufreq_probe(struct pla
- return -ENOENT;
- }
-
-- speedbin_nvmem = of_nvmem_cell_get(np, NULL);
-- of_node_put(np);
-- if (IS_ERR(speedbin_nvmem)) {
-- if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER)
-- dev_err(cpu_dev, "Could not get nvmem cell: %ld\n",
-- PTR_ERR(speedbin_nvmem));
-- return PTR_ERR(speedbin_nvmem);
-+ drv = kzalloc(sizeof(*drv), GFP_KERNEL);
-+ if (!drv)
-+ return -ENOMEM;
-+
-+ match = pdev->dev.platform_data;
-+ drv->data = match->data;
-+ if (!drv->data) {
-+ ret = -ENODEV;
-+ goto free_drv;
- }
-
-- ret = get_version(cpu_dev, speedbin_nvmem, &versions);
-- nvmem_cell_put(speedbin_nvmem);
-- if (ret)
-- return ret;
-+ if (drv->data->get_version) {
-+ speedbin_nvmem = of_nvmem_cell_get(np, NULL);
-+ if (IS_ERR(speedbin_nvmem)) {
-+ if (PTR_ERR(speedbin_nvmem) != -EPROBE_DEFER)
-+ dev_err(cpu_dev,
-+ "Could not get nvmem cell: %ld\n",
-+ PTR_ERR(speedbin_nvmem));
-+ ret = PTR_ERR(speedbin_nvmem);
-+ goto free_drv;
-+ }
-
-- opp_tables = kcalloc(num_possible_cpus(), sizeof(*opp_tables), GFP_KERNEL);
-- if (!opp_tables)
-- return -ENOMEM;
-+ ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv);
-+ if (ret) {
-+ nvmem_cell_put(speedbin_nvmem);
-+ goto free_drv;
-+ }
-+ nvmem_cell_put(speedbin_nvmem);
-+ }
-+ of_node_put(np);
-+
-+ drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables),
-+ GFP_KERNEL);
-+ if (!drv->opp_tables) {
-+ ret = -ENOMEM;
-+ goto free_drv;
-+ }
-
- for_each_possible_cpu(cpu) {
- cpu_dev = get_cpu_device(cpu);
-@@ -166,19 +195,23 @@ static int qcom_cpufreq_probe(struct pla
- goto free_opp;
- }
-
-- opp_tables[cpu] = dev_pm_opp_set_supported_hw(cpu_dev,
-- &versions, 1);
-- if (IS_ERR(opp_tables[cpu])) {
-- ret = PTR_ERR(opp_tables[cpu]);
-- dev_err(cpu_dev, "Failed to set supported hardware\n");
-- goto free_opp;
-+ if (drv->data->get_version) {
-+ drv->opp_tables[cpu] =
-+ dev_pm_opp_set_supported_hw(cpu_dev,
-+ &drv->versions, 1);
-+ if (IS_ERR(drv->opp_tables[cpu])) {
-+ ret = PTR_ERR(drv->opp_tables[cpu]);
-+ dev_err(cpu_dev,
-+ "Failed to set supported hardware\n");
-+ goto free_opp;
-+ }
- }
- }
-
- cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
- NULL, 0);
- if (!IS_ERR(cpufreq_dt_pdev)) {
-- platform_set_drvdata(pdev, opp_tables);
-+ platform_set_drvdata(pdev, drv);
- return 0;
- }
-
-@@ -187,26 +220,30 @@ static int qcom_cpufreq_probe(struct pla
-
- free_opp:
- for_each_possible_cpu(cpu) {
-- if (IS_ERR_OR_NULL(opp_tables[cpu]))
-+ if (IS_ERR_OR_NULL(drv->opp_tables[cpu]))
- break;
-- dev_pm_opp_put_supported_hw(opp_tables[cpu]);
-+ dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
- }
-- kfree(opp_tables);
-+ kfree(drv->opp_tables);
-+free_drv:
-+ kfree(drv);
-
- return ret;
- }
-
- static int qcom_cpufreq_remove(struct platform_device *pdev)
- {
-- struct opp_table **opp_tables = platform_get_drvdata(pdev);
-+ struct qcom_cpufreq_drv *drv = platform_get_drvdata(pdev);
- unsigned int cpu;
-
- platform_device_unregister(cpufreq_dt_pdev);
-
- for_each_possible_cpu(cpu)
-- dev_pm_opp_put_supported_hw(opp_tables[cpu]);
-+ if (drv->opp_tables[cpu])
-+ dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
-
-- kfree(opp_tables);
-+ kfree(drv->opp_tables);
-+ kfree(drv);
-
- return 0;
- }
-@@ -220,10 +257,8 @@ static struct platform_driver qcom_cpufr
- };
-
- static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
-- { .compatible = "qcom,apq8096",
-- .data = qcom_cpufreq_kryo_name_version },
-- { .compatible = "qcom,msm8996",
-- .data = qcom_cpufreq_kryo_name_version },
-+ { .compatible = "qcom,apq8096", .data = &match_data_kryo },
-+ { .compatible = "qcom,msm8996", .data = &match_data_kryo },
- {},
- };
-
+++ /dev/null
-Check for SCM availability before attempting to use SPM
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-
---- a/drivers/soc/qcom/spm.c
-+++ b/drivers/soc/qcom/spm.c
-@@ -214,6 +214,9 @@ static int __init qcom_cpuidle_init(stru
- if (!qcom_scm_is_available())
- return -EPROBE_DEFER;
-
-+ if (!qcom_scm_is_available())
-+ return -EPROBE_DEFER;
-+
- for (i = 0; ; i++) {
- state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
- if (!state_node)