181b91f6eb25c71b270b717f46c2fa6804b75f51
[openwrt/openwrt.git] / target / linux / ipq806x / patches-4.19 / 0034-0007-clk-qcom-Add-support-for-Krait-clocks.patch
1 From 4d7dc77babfef1d6cb8fd825e2f17dc3384c3272 Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Tue, 14 Aug 2018 17:42:26 +0530
4 Subject: [PATCH 07/12] clk: qcom: Add support for Krait clocks
5
6 The Krait clocks are made up of a series of muxes and a divider
7 that choose between a fixed rate clock and dedicated HFPLLs for
8 each CPU. Instead of using mmio accesses to remux parents, the
9 Krait implementation exposes the remux control via cp15
10 registers. Support these clocks.
11
12 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
13 Signed-off-by: Sricharan R <sricharan@codeaurora.org>
14 Tested-by: Craig Tatlor <ctatlor97@gmail.com>
15 [sboyd@kernel.org: Move hidden config to top outside of the visible qcom
16 config zone so that menuconfig looks nice]
17 Signed-off-by: Stephen Boyd <sboyd@kernel.org>
18 ---
19 drivers/clk/qcom/Kconfig | 4 ++
20 drivers/clk/qcom/Makefile | 1 +
21 drivers/clk/qcom/clk-krait.c | 124 +++++++++++++++++++++++++++++++++++
22 drivers/clk/qcom/clk-krait.h | 37 +++++++++++
23 4 files changed, 166 insertions(+)
24 create mode 100644 drivers/clk/qcom/clk-krait.c
25 create mode 100644 drivers/clk/qcom/clk-krait.h
26
27 --- a/drivers/clk/qcom/Kconfig
28 +++ b/drivers/clk/qcom/Kconfig
29 @@ -1,3 +1,7 @@
30 +config KRAIT_CLOCKS
31 + bool
32 + select KRAIT_L2_ACCESSORS
33 +
34 config QCOM_GDSC
35 bool
36 select PM_GENERIC_DOMAINS if PM
37 --- a/drivers/clk/qcom/Makefile
38 +++ b/drivers/clk/qcom/Makefile
39 @@ -11,6 +11,7 @@ clk-qcom-y += clk-branch.o
40 clk-qcom-y += clk-regmap-divider.o
41 clk-qcom-y += clk-regmap-mux.o
42 clk-qcom-y += clk-regmap-mux-div.o
43 +clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
44 clk-qcom-y += clk-hfpll.o
45 clk-qcom-y += reset.o
46 clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
47 --- /dev/null
48 +++ b/drivers/clk/qcom/clk-krait.c
49 @@ -0,0 +1,124 @@
50 +// SPDX-License-Identifier: GPL-2.0
51 +// Copyright (c) 2018, The Linux Foundation. All rights reserved.
52 +
53 +#include <linux/kernel.h>
54 +#include <linux/module.h>
55 +#include <linux/init.h>
56 +#include <linux/io.h>
57 +#include <linux/delay.h>
58 +#include <linux/err.h>
59 +#include <linux/clk-provider.h>
60 +#include <linux/spinlock.h>
61 +
62 +#include <asm/krait-l2-accessors.h>
63 +
64 +#include "clk-krait.h"
65 +
66 +/* Secondary and primary muxes share the same cp15 register */
67 +static DEFINE_SPINLOCK(krait_clock_reg_lock);
68 +
69 +#define LPL_SHIFT 8
70 +static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel)
71 +{
72 + unsigned long flags;
73 + u32 regval;
74 +
75 + spin_lock_irqsave(&krait_clock_reg_lock, flags);
76 + regval = krait_get_l2_indirect_reg(mux->offset);
77 + regval &= ~(mux->mask << mux->shift);
78 + regval |= (sel & mux->mask) << mux->shift;
79 + if (mux->lpl) {
80 + regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
81 + regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
82 + }
83 + krait_set_l2_indirect_reg(mux->offset, regval);
84 + spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
85 +
86 + /* Wait for switch to complete. */
87 + mb();
88 + udelay(1);
89 +}
90 +
91 +static int krait_mux_set_parent(struct clk_hw *hw, u8 index)
92 +{
93 + struct krait_mux_clk *mux = to_krait_mux_clk(hw);
94 + u32 sel;
95 +
96 + sel = clk_mux_reindex(index, mux->parent_map, 0);
97 + mux->en_mask = sel;
98 + /* Don't touch mux if CPU is off as it won't work */
99 + if (__clk_is_enabled(hw->clk))
100 + __krait_mux_set_sel(mux, sel);
101 +
102 + return 0;
103 +}
104 +
105 +static u8 krait_mux_get_parent(struct clk_hw *hw)
106 +{
107 + struct krait_mux_clk *mux = to_krait_mux_clk(hw);
108 + u32 sel;
109 +
110 + sel = krait_get_l2_indirect_reg(mux->offset);
111 + sel >>= mux->shift;
112 + sel &= mux->mask;
113 + mux->en_mask = sel;
114 +
115 + return clk_mux_get_parent(hw, sel, mux->parent_map, 0);
116 +}
117 +
118 +const struct clk_ops krait_mux_clk_ops = {
119 + .set_parent = krait_mux_set_parent,
120 + .get_parent = krait_mux_get_parent,
121 + .determine_rate = __clk_mux_determine_rate_closest,
122 +};
123 +EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
124 +
125 +/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
126 +static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate,
127 + unsigned long *parent_rate)
128 +{
129 + *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2);
130 + return DIV_ROUND_UP(*parent_rate, 2);
131 +}
132 +
133 +static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,
134 + unsigned long parent_rate)
135 +{
136 + struct krait_div2_clk *d = to_krait_div2_clk(hw);
137 + unsigned long flags;
138 + u32 val;
139 + u32 mask = BIT(d->width) - 1;
140 +
141 + if (d->lpl)
142 + mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift;
143 +
144 + spin_lock_irqsave(&krait_clock_reg_lock, flags);
145 + val = krait_get_l2_indirect_reg(d->offset);
146 + val &= ~mask;
147 + krait_set_l2_indirect_reg(d->offset, val);
148 + spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
149 +
150 + return 0;
151 +}
152 +
153 +static unsigned long
154 +krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
155 +{
156 + struct krait_div2_clk *d = to_krait_div2_clk(hw);
157 + u32 mask = BIT(d->width) - 1;
158 + u32 div;
159 +
160 + div = krait_get_l2_indirect_reg(d->offset);
161 + div >>= d->shift;
162 + div &= mask;
163 + div = (div + 1) * 2;
164 +
165 + return DIV_ROUND_UP(parent_rate, div);
166 +}
167 +
168 +const struct clk_ops krait_div2_clk_ops = {
169 + .round_rate = krait_div2_round_rate,
170 + .set_rate = krait_div2_set_rate,
171 + .recalc_rate = krait_div2_recalc_rate,
172 +};
173 +EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
174 --- /dev/null
175 +++ b/drivers/clk/qcom/clk-krait.h
176 @@ -0,0 +1,37 @@
177 +/* SPDX-License-Identifier: GPL-2.0 */
178 +
179 +#ifndef __QCOM_CLK_KRAIT_H
180 +#define __QCOM_CLK_KRAIT_H
181 +
182 +#include <linux/clk-provider.h>
183 +
184 +struct krait_mux_clk {
185 + unsigned int *parent_map;
186 + u32 offset;
187 + u32 mask;
188 + u32 shift;
189 + u32 en_mask;
190 + bool lpl;
191 +
192 + struct clk_hw hw;
193 + struct notifier_block clk_nb;
194 +};
195 +
196 +#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)
197 +
198 +extern const struct clk_ops krait_mux_clk_ops;
199 +
200 +struct krait_div2_clk {
201 + u32 offset;
202 + u8 width;
203 + u32 shift;
204 + bool lpl;
205 +
206 + struct clk_hw hw;
207 +};
208 +
209 +#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw)
210 +
211 +extern const struct clk_ops krait_div2_clk_ops;
212 +
213 +#endif