aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ipq806x/patches-4.9/0041-clk-qcom-Add-support-for-Krait-clocks.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ipq806x/patches-4.9/0041-clk-qcom-Add-support-for-Krait-clocks.patch')
-rw-r--r--target/linux/ipq806x/patches-4.9/0041-clk-qcom-Add-support-for-Krait-clocks.patch263
1 files changed, 263 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches-4.9/0041-clk-qcom-Add-support-for-Krait-clocks.patch b/target/linux/ipq806x/patches-4.9/0041-clk-qcom-Add-support-for-Krait-clocks.patch
new file mode 100644
index 0000000000..902e49d60c
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.9/0041-clk-qcom-Add-support-for-Krait-clocks.patch
@@ -0,0 +1,263 @@
+From b9747125a8e7633ed2701a70e32dbb0442193774 Mon Sep 17 00:00:00 2001
+From: Stephen Boyd <sboyd@codeaurora.org>
+Date: Fri, 20 Mar 2015 23:45:28 -0700
+Subject: [PATCH 41/69] 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>
+---
+ drivers/clk/qcom/Kconfig | 4 ++
+ drivers/clk/qcom/Makefile | 1 +
+ drivers/clk/qcom/clk-krait.c | 167 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/clk/qcom/clk-krait.h | 49 +++++++++++++
+ 4 files changed, 221 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
+@@ -187,3 +187,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
+@@ -9,6 +9,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,167 @@
++/*
++ * 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);
++}
++
++static struct clk_hw *krait_mux_get_safe_parent(struct clk_hw *hw,
++ unsigned long *safe_freq)
++{
++ int i;
++ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
++ int num_parents = clk_hw_get_num_parents(hw);
++
++ i = mux->safe_sel;
++ for (i = 0; i < num_parents; i++)
++ if (mux->safe_sel == mux->parent_map[i])
++ break;
++
++ return clk_hw_get_parent_by_index(hw, i);
++}
++
++static int krait_mux_enable(struct clk_hw *hw)
++{
++ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
++
++ __krait_mux_set_sel(mux, mux->en_mask);
++
++ return 0;
++}
++
++static void krait_mux_disable(struct clk_hw *hw)
++{
++ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
++
++ __krait_mux_set_sel(mux, mux->safe_sel);
++}
++
++const struct clk_ops krait_mux_clk_ops = {
++ .enable = krait_mux_enable,
++ .disable = krait_mux_disable,
++ .set_parent = krait_mux_set_parent,
++ .get_parent = krait_mux_get_parent,
++ .determine_rate = __clk_mux_determine_rate_closest,
++ .get_safe_parent = krait_mux_get_safe_parent,
++};
++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,49 @@
++/*
++ * 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;
++ bool has_safe_parent;
++ u8 safe_sel;
++ u32 offset;
++ u32 mask;
++ u32 shift;
++ u32 en_mask;
++ bool lpl;
++
++ struct clk_hw hw;
++};
++
++#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