Refreshed all patches Compile-tested on: cns3xxx, imx6, x86_64 Runtime-tested on: cns3xxx, imx6, x86_64 Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com> Tested-by: Michael Yartys <michael.yartys@protonmail.com>
		
			
				
	
	
		
			242 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From patchwork Fri Dec  8 09:42:25 2017
 | 
						|
Content-Type: text/plain; charset="utf-8"
 | 
						|
MIME-Version: 1.0
 | 
						|
Content-Transfer-Encoding: 7bit
 | 
						|
Subject: [v4,07/12] clk: qcom: Add support for Krait clocks
 | 
						|
From: Sricharan R <sricharan@codeaurora.org>
 | 
						|
X-Patchwork-Id: 10102051
 | 
						|
Message-Id: <1512726150-7204-8-git-send-email-sricharan@codeaurora.org>
 | 
						|
To: mturquette@baylibre.com, sboyd@codeaurora.org,
 | 
						|
 devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
 | 
						|
 linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
 | 
						|
 viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
 | 
						|
Cc: sricharan@codeaurora.org
 | 
						|
Date: Fri,  8 Dec 2017 15:12:25 +0530
 | 
						|
 | 
						|
From: Stephen Boyd <sboyd@codeaurora.org>
 | 
						|
 | 
						|
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>
 | 
						|
---
 | 
						|
 drivers/clk/qcom/Kconfig     |   4 ++
 | 
						|
 drivers/clk/qcom/Makefile    |   1 +
 | 
						|
 drivers/clk/qcom/clk-krait.c | 134 +++++++++++++++++++++++++++++++++++++++++++
 | 
						|
 drivers/clk/qcom/clk-krait.h |  48 ++++++++++++++++
 | 
						|
 4 files changed, 187 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
 | 
						|
@@ -204,3 +204,7 @@ 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 KRAIT_CLOCKS
 | 
						|
+	bool
 | 
						|
+	select KRAIT_L2_ACCESSORS
 | 
						|
--- a/drivers/clk/qcom/Makefile
 | 
						|
+++ b/drivers/clk/qcom/Makefile
 | 
						|
@@ -10,6 +10,7 @@ clk-qcom-y += clk-rcg2.o
 | 
						|
 clk-qcom-y += clk-branch.o
 | 
						|
 clk-qcom-y += clk-regmap-divider.o
 | 
						|
 clk-qcom-y += clk-regmap-mux.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,134 @@
 | 
						|
+/*
 | 
						|
+ * Copyright (c) 2013-2014, 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.
 | 
						|
+ */
 | 
						|
+
 | 
						|
+#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,48 @@
 | 
						|
+/*
 | 
						|
+ * Copyright (c) 2013, 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 __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
 |