aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ipq806x/patches-4.9/0057-clk-qcom-Add-regmap-mux-div-clocks-support.patch
diff options
context:
space:
mode:
authorPavel Kubelun <be.dissent@gmail.com>2017-12-09 20:15:05 +0300
committerFelix Fietkau <nbd@nbd.name>2018-01-17 11:02:05 +0100
commit7903a9219c7eb5d14c62f79d4a70f5cab1c6294f (patch)
treed72252a2bc48c698d89a28b7b923da0b1b115827 /target/linux/ipq806x/patches-4.9/0057-clk-qcom-Add-regmap-mux-div-clocks-support.patch
parent83499bef73cc67b9290360cf76c345a7b3c29f08 (diff)
downloadupstream-7903a9219c7eb5d14c62f79d4a70f5cab1c6294f.tar.gz
upstream-7903a9219c7eb5d14c62f79d4a70f5cab1c6294f.tar.bz2
upstream-7903a9219c7eb5d14c62f79d4a70f5cab1c6294f.zip
ipq806x: update clk and cpufreq drivers
A newer clk and cpufreq drivers for ipq806x platform had been sent upstream. A change that i have noticed is that now it's possible to set min, cur and max frequencies from sysfs (previously it was bugged and caused nothing). Following patches are removed: - 0036-clk-Avoid-sending-high-rates-to-downstream-clocks-du.patch - seems it was dropped from the patchset by current committer. - 0044-clk-qcom-krait-Remove-CLK_IS_ROOT.patch - already applied to the driver itself in the corresponding patch. - 0057-clk-qcom-Add-regmap-mux-div-clocks-support.patch - seem to be irrelevant to ipq806x. Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
Diffstat (limited to 'target/linux/ipq806x/patches-4.9/0057-clk-qcom-Add-regmap-mux-div-clocks-support.patch')
-rw-r--r--target/linux/ipq806x/patches-4.9/0057-clk-qcom-Add-regmap-mux-div-clocks-support.patch372
1 files changed, 0 insertions, 372 deletions
diff --git a/target/linux/ipq806x/patches-4.9/0057-clk-qcom-Add-regmap-mux-div-clocks-support.patch b/target/linux/ipq806x/patches-4.9/0057-clk-qcom-Add-regmap-mux-div-clocks-support.patch
deleted file mode 100644
index c5cdc79300..0000000000
--- a/target/linux/ipq806x/patches-4.9/0057-clk-qcom-Add-regmap-mux-div-clocks-support.patch
+++ /dev/null
@@ -1,372 +0,0 @@
-From f72c5aa18281c44945fea6181d0d816a7605505c Mon Sep 17 00:00:00 2001
-From: Georgi Djakov <georgi.djakov@linaro.org>
-Date: Wed, 18 Mar 2015 17:23:29 +0200
-Subject: [PATCH 57/69] clk: qcom: Add regmap mux-div clocks support
-
-Add support for hardware that can switch both parent clocks and divider
-at the same time. This avoids generating intermediate frequencies from
-either the old parent clock and new divider or new parent clock and
-old divider combinations.
-
-Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
----
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/clk-regmap-mux-div.c | 272 ++++++++++++++++++++++++++++++++++
- drivers/clk/qcom/clk-regmap-mux-div.h | 65 ++++++++
- 3 files changed, 338 insertions(+)
- create mode 100644 drivers/clk/qcom/clk-regmap-mux-div.c
- create mode 100644 drivers/clk/qcom/clk-regmap-mux-div.h
-
---- 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-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
---- /dev/null
-+++ b/drivers/clk/qcom/clk-regmap-mux-div.c
-@@ -0,0 +1,272 @@
-+/*
-+ * Copyright (c) 2015, Linaro Limited
-+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/bitops.h>
-+#include <linux/delay.h>
-+#include <linux/export.h>
-+#include <linux/kernel.h>
-+#include <linux/regmap.h>
-+
-+#include "clk-regmap-mux-div.h"
-+
-+#define CMD_RCGR 0x0
-+#define CMD_RCGR_UPDATE BIT(0)
-+#define CMD_RCGR_DIRTY_CFG BIT(4)
-+#define CMD_RCGR_ROOT_OFF BIT(31)
-+#define CFG_RCGR 0x4
-+
-+#define to_clk_regmap_mux_div(_hw) \
-+ container_of(to_clk_regmap(_hw), struct clk_regmap_mux_div, clkr)
-+
-+int __mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div)
-+{
-+ int ret, count;
-+ u32 val, mask;
-+ const char *name = clk_hw_get_name(&md->clkr.hw);
-+
-+ val = (div << md->hid_shift) | (src << md->src_shift);
-+ mask = ((BIT(md->hid_width) - 1) << md->hid_shift) |
-+ ((BIT(md->src_width) - 1) << md->src_shift);
-+
-+ ret = regmap_update_bits(md->clkr.regmap, CFG_RCGR + md->reg_offset,
-+ mask, val);
-+ if (ret)
-+ return ret;
-+
-+ ret = regmap_update_bits(md->clkr.regmap, CMD_RCGR + md->reg_offset,
-+ CMD_RCGR_UPDATE, CMD_RCGR_UPDATE);
-+ if (ret)
-+ return ret;
-+
-+ /* Wait for update to take effect */
-+ for (count = 500; count > 0; count--) {
-+ ret = regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset,
-+ &val);
-+ if (ret)
-+ return ret;
-+ if (!(val & CMD_RCGR_UPDATE))
-+ return 0;
-+ udelay(1);
-+ }
-+
-+ pr_err("%s: RCG did not update its configuration", name);
-+ return -EBUSY;
-+}
-+
-+static void __mux_div_get_src_div(struct clk_regmap_mux_div *md, u32 *src,
-+ u32 *div)
-+{
-+ u32 val, __div, __src;
-+ const char *name = clk_hw_get_name(&md->clkr.hw);
-+
-+ regmap_read(md->clkr.regmap, CMD_RCGR + md->reg_offset, &val);
-+
-+ if (val & CMD_RCGR_DIRTY_CFG) {
-+ pr_err("%s: RCG configuration is pending\n", name);
-+ return;
-+ }
-+
-+ regmap_read(md->clkr.regmap, CFG_RCGR + md->reg_offset, &val);
-+ __src = (val >> md->src_shift);
-+ __src &= BIT(md->src_width) - 1;
-+ *src = __src;
-+
-+ __div = (val >> md->hid_shift);
-+ __div &= BIT(md->hid_width) - 1;
-+ *div = __div;
-+}
-+
-+static int mux_div_enable(struct clk_hw *hw)
-+{
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+
-+ return __mux_div_set_src_div(md, md->src, md->div);
-+}
-+
-+static inline bool is_better_rate(unsigned long req, unsigned long best,
-+ unsigned long new)
-+{
-+ return (req <= new && new < best) || (best < req && best < new);
-+}
-+
-+static int mux_div_determine_rate(struct clk_hw *hw,
-+ struct clk_rate_request *req)
-+{
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+ unsigned int i, div, max_div;
-+ unsigned long actual_rate, best_rate = 0;
-+ unsigned long req_rate = req->rate;
-+
-+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
-+ struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
-+ unsigned long parent_rate = clk_hw_get_rate(parent);
-+
-+ max_div = BIT(md->hid_width) - 1;
-+ for (div = 1; div < max_div; div++) {
-+ parent_rate = mult_frac(req_rate, div, 2);
-+ parent_rate = clk_hw_round_rate(parent, parent_rate);
-+ actual_rate = mult_frac(parent_rate, 2, div);
-+
-+ if (is_better_rate(req_rate, best_rate, actual_rate)) {
-+ best_rate = actual_rate;
-+ req->rate = best_rate;
-+ req->best_parent_rate = parent_rate;
-+ req->best_parent_hw = parent;
-+ }
-+
-+ if (actual_rate < req_rate || best_rate <= req_rate)
-+ break;
-+ }
-+ }
-+
-+ if (!best_rate)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static int __mux_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
-+ unsigned long prate, u32 src)
-+{
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+ int ret;
-+ u32 div, max_div, best_src = 0, best_div = 0;
-+ unsigned int i;
-+ unsigned long actual_rate, best_rate = 0;
-+
-+ for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
-+ struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
-+ unsigned long parent_rate = clk_hw_get_rate(parent);
-+
-+ max_div = BIT(md->hid_width) - 1;
-+ for (div = 1; div < max_div; div++) {
-+ parent_rate = mult_frac(rate, div, 2);
-+ parent_rate = clk_hw_round_rate(parent, parent_rate);
-+ actual_rate = mult_frac(parent_rate, 2, div);
-+
-+ if (is_better_rate(rate, best_rate, actual_rate)) {
-+ best_rate = actual_rate;
-+ best_src = md->parent_map[i].cfg;
-+ best_div = div - 1;
-+ }
-+
-+ if (actual_rate < rate || best_rate <= rate)
-+ break;
-+ }
-+ }
-+
-+ ret = __mux_div_set_src_div(md, best_src, best_div);
-+ if (!ret) {
-+ md->div = best_div;
-+ md->src = best_src;
-+ }
-+
-+ return ret;
-+}
-+
-+static u8 mux_div_get_parent(struct clk_hw *hw)
-+{
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+ const char *name = clk_hw_get_name(hw);
-+ u32 i, div, src = 0;
-+
-+ __mux_div_get_src_div(md, &src, &div);
-+
-+ for (i = 0; i < clk_hw_get_num_parents(hw); i++)
-+ if (src == md->parent_map[i].cfg)
-+ return i;
-+
-+ pr_err("%s: Can't find parent with src %d\n", name, src);
-+ return 0;
-+}
-+
-+static int mux_div_set_parent(struct clk_hw *hw, u8 index)
-+{
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+
-+ return __mux_div_set_src_div(md, md->parent_map[index].cfg, md->div);
-+}
-+
-+static int mux_div_set_rate(struct clk_hw *hw,
-+ unsigned long rate, unsigned long prate)
-+{
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+
-+ return __mux_div_set_rate_and_parent(hw, rate, prate, md->src);
-+}
-+
-+static int mux_div_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
-+ unsigned long prate, u8 index)
-+{
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+
-+ return __mux_div_set_rate_and_parent(hw, rate, prate,
-+ md->parent_map[index].cfg);
-+}
-+
-+static unsigned long mux_div_recalc_rate(struct clk_hw *hw, unsigned long prate)
-+{
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+ u32 div, src;
-+ int i, num_parents = clk_hw_get_num_parents(hw);
-+ const char *name = clk_hw_get_name(hw);
-+
-+ __mux_div_get_src_div(md, &src, &div);
-+ for (i = 0; i < num_parents; i++)
-+ if (src == md->parent_map[i].cfg) {
-+ struct clk_hw *p = clk_hw_get_parent_by_index(hw, i);
-+ unsigned long parent_rate = clk_hw_get_rate(p);
-+
-+ return mult_frac(parent_rate, 2, div + 1);
-+ }
-+
-+ pr_err("%s: Can't find parent %d\n", name, src);
-+ return 0;
-+}
-+
-+static struct clk_hw *mux_div_get_safe_parent(struct clk_hw *hw,
-+ unsigned long *safe_freq)
-+{
-+ int i;
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+
-+ if (md->safe_freq)
-+ *safe_freq = md->safe_freq;
-+
-+ for (i = 0; i < clk_hw_get_num_parents(hw); i++)
-+ if (md->safe_src == md->parent_map[i].cfg)
-+ break;
-+
-+ return clk_hw_get_parent_by_index(hw, i);
-+}
-+
-+static void mux_div_disable(struct clk_hw *hw)
-+{
-+ struct clk_regmap_mux_div *md = to_clk_regmap_mux_div(hw);
-+
-+ __mux_div_set_src_div(md, md->safe_src, md->safe_div);
-+}
-+
-+const struct clk_ops clk_regmap_mux_div_ops = {
-+ .enable = mux_div_enable,
-+ .disable = mux_div_disable,
-+ .get_parent = mux_div_get_parent,
-+ .set_parent = mux_div_set_parent,
-+ .set_rate = mux_div_set_rate,
-+ .set_rate_and_parent = mux_div_set_rate_and_parent,
-+ .determine_rate = mux_div_determine_rate,
-+ .recalc_rate = mux_div_recalc_rate,
-+ .get_safe_parent = mux_div_get_safe_parent,
-+};
-+EXPORT_SYMBOL_GPL(clk_regmap_mux_div_ops);
---- /dev/null
-+++ b/drivers/clk/qcom/clk-regmap-mux-div.h
-@@ -0,0 +1,65 @@
-+/*
-+ * Copyright (c) 2015, Linaro Limited
-+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __QCOM_CLK_REGMAP_MUX_DIV_H__
-+#define __QCOM_CLK_REGMAP_MUX_DIV_H__
-+
-+#include <linux/clk-provider.h>
-+#include "clk-rcg.h"
-+#include "clk-regmap.h"
-+
-+/**
-+ * struct mux_div_clk - combined mux/divider clock
-+ * @reg_offset: offset of the mux/divider register
-+ * @hid_width: number of bits in half integer divider
-+ * @hid_shift: lowest bit of hid value field
-+ * @src_width: number of bits in source select
-+ * @src_shift: lowest bit of source select field
-+ * @div: the divider raw configuration value
-+ * @src: the mux index which will be used if the clock is enabled
-+ * @safe_src: the safe source mux value we switch to, while the main PLL is
-+ * reconfigured
-+ * @safe_div: the safe divider value that we set, while the main PLL is
-+ * reconfigured
-+ * @safe_freq: When switching rates from A to B, the mux div clock will
-+ * instead switch from A -> safe_freq -> B. This allows the
-+ * mux_div clock to change rates while enabled, even if this
-+ * behavior is not supported by the parent clocks.
-+ * If changing the rate of parent A also causes the rate of
-+ * parent B to change, then safe_freq must be defined.
-+ * safe_freq is expected to have a source clock which is always
-+ * on and runs at only one rate.
-+ * @parent_map: pointer to parent_map struct
-+ * @clkr: handle between common and hardware-specific interfaces
-+ */
-+
-+struct clk_regmap_mux_div {
-+ u32 reg_offset;
-+ u32 hid_width;
-+ u32 hid_shift;
-+ u32 src_width;
-+ u32 src_shift;
-+ u32 div;
-+ u32 src;
-+ u32 safe_src;
-+ u32 safe_div;
-+ unsigned long safe_freq;
-+ const struct parent_map *parent_map;
-+ struct clk_regmap clkr;
-+};
-+
-+extern const struct clk_ops clk_regmap_mux_div_ops;
-+int __mux_div_set_src_div(struct clk_regmap_mux_div *md, u32 src, u32 div);
-+
-+#endif