ipq806x: enable QCE hardware crypto inside the kernel
[oweals/openwrt.git] / target / linux / ipq806x / patches-4.9 / 0041-clk-qcom-Add-support-for-Krait-clocks.patch
1 From b9747125a8e7633ed2701a70e32dbb0442193774 Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Fri, 20 Mar 2015 23:45:28 -0700
4 Subject: [PATCH 41/69] 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 ---
14  drivers/clk/qcom/Kconfig     |   4 ++
15  drivers/clk/qcom/Makefile    |   1 +
16  drivers/clk/qcom/clk-krait.c | 167 +++++++++++++++++++++++++++++++++++++++++++
17  drivers/clk/qcom/clk-krait.h |  49 +++++++++++++
18  4 files changed, 221 insertions(+)
19  create mode 100644 drivers/clk/qcom/clk-krait.c
20  create mode 100644 drivers/clk/qcom/clk-krait.h
21
22 --- a/drivers/clk/qcom/Kconfig
23 +++ b/drivers/clk/qcom/Kconfig
24 @@ -187,3 +187,7 @@ config QCOM_HFPLL
25           Support for the high-frequency PLLs present on Qualcomm devices.
26           Say Y if you want to support CPU frequency scaling on devices
27           such as MSM8974, APQ8084, etc.
28 +
29 +config KRAIT_CLOCKS
30 +       bool
31 +       select KRAIT_L2_ACCESSORS
32 --- a/drivers/clk/qcom/Makefile
33 +++ b/drivers/clk/qcom/Makefile
34 @@ -9,6 +9,7 @@ clk-qcom-y += clk-rcg2.o
35  clk-qcom-y += clk-branch.o
36  clk-qcom-y += clk-regmap-divider.o
37  clk-qcom-y += clk-regmap-mux.o
38 +clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
39  clk-qcom-y += clk-hfpll.o
40  clk-qcom-y += reset.o
41  clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
42 --- /dev/null
43 +++ b/drivers/clk/qcom/clk-krait.c
44 @@ -0,0 +1,167 @@
45 +/*
46 + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
47 + *
48 + * This program is free software; you can redistribute it and/or modify
49 + * it under the terms of the GNU General Public License version 2 and
50 + * only version 2 as published by the Free Software Foundation.
51 + *
52 + * This program is distributed in the hope that it will be useful,
53 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
54 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
55 + * GNU General Public License for more details.
56 + */
57 +
58 +#include <linux/kernel.h>
59 +#include <linux/module.h>
60 +#include <linux/init.h>
61 +#include <linux/io.h>
62 +#include <linux/delay.h>
63 +#include <linux/err.h>
64 +#include <linux/clk-provider.h>
65 +#include <linux/spinlock.h>
66 +
67 +#include <asm/krait-l2-accessors.h>
68 +
69 +#include "clk-krait.h"
70 +
71 +/* Secondary and primary muxes share the same cp15 register */
72 +static DEFINE_SPINLOCK(krait_clock_reg_lock);
73 +
74 +#define LPL_SHIFT      8
75 +static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel)
76 +{
77 +       unsigned long flags;
78 +       u32 regval;
79 +
80 +       spin_lock_irqsave(&krait_clock_reg_lock, flags);
81 +       regval = krait_get_l2_indirect_reg(mux->offset);
82 +       regval &= ~(mux->mask << mux->shift);
83 +       regval |= (sel & mux->mask) << mux->shift;
84 +       if (mux->lpl) {
85 +               regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
86 +               regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
87 +       }
88 +       krait_set_l2_indirect_reg(mux->offset, regval);
89 +       spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
90 +
91 +       /* Wait for switch to complete. */
92 +       mb();
93 +       udelay(1);
94 +}
95 +
96 +static int krait_mux_set_parent(struct clk_hw *hw, u8 index)
97 +{
98 +       struct krait_mux_clk *mux = to_krait_mux_clk(hw);
99 +       u32 sel;
100 +
101 +       sel = clk_mux_reindex(index, mux->parent_map, 0);
102 +       mux->en_mask = sel;
103 +       /* Don't touch mux if CPU is off as it won't work */
104 +       if (__clk_is_enabled(hw->clk))
105 +               __krait_mux_set_sel(mux, sel);
106 +       return 0;
107 +}
108 +
109 +static u8 krait_mux_get_parent(struct clk_hw *hw)
110 +{
111 +       struct krait_mux_clk *mux = to_krait_mux_clk(hw);
112 +       u32 sel;
113 +
114 +       sel = krait_get_l2_indirect_reg(mux->offset);
115 +       sel >>= mux->shift;
116 +       sel &= mux->mask;
117 +       mux->en_mask = sel;
118 +
119 +       return clk_mux_get_parent(hw, sel, mux->parent_map, 0);
120 +}
121 +
122 +static struct clk_hw *krait_mux_get_safe_parent(struct clk_hw *hw,
123 +                                               unsigned long *safe_freq)
124 +{
125 +       int i;
126 +       struct krait_mux_clk *mux = to_krait_mux_clk(hw);
127 +       int num_parents = clk_hw_get_num_parents(hw);
128 +
129 +       i = mux->safe_sel;
130 +       for (i = 0; i < num_parents; i++)
131 +               if (mux->safe_sel == mux->parent_map[i])
132 +                       break;
133 +
134 +       return clk_hw_get_parent_by_index(hw, i);
135 +}
136 +
137 +static int krait_mux_enable(struct clk_hw *hw)
138 +{
139 +       struct krait_mux_clk *mux = to_krait_mux_clk(hw);
140 +
141 +       __krait_mux_set_sel(mux, mux->en_mask);
142 +
143 +       return 0;
144 +}
145 +
146 +static void krait_mux_disable(struct clk_hw *hw)
147 +{
148 +       struct krait_mux_clk *mux = to_krait_mux_clk(hw);
149 +
150 +       __krait_mux_set_sel(mux, mux->safe_sel);
151 +}
152 +
153 +const struct clk_ops krait_mux_clk_ops = {
154 +       .enable = krait_mux_enable,
155 +       .disable = krait_mux_disable,
156 +       .set_parent = krait_mux_set_parent,
157 +       .get_parent = krait_mux_get_parent,
158 +       .determine_rate = __clk_mux_determine_rate_closest,
159 +       .get_safe_parent = krait_mux_get_safe_parent,
160 +};
161 +EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
162 +
163 +/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
164 +static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate,
165 +                                 unsigned long *parent_rate)
166 +{
167 +       *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2);
168 +       return DIV_ROUND_UP(*parent_rate, 2);
169 +}
170 +
171 +static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,
172 +                       unsigned long parent_rate)
173 +{
174 +       struct krait_div2_clk *d = to_krait_div2_clk(hw);
175 +       unsigned long flags;
176 +       u32 val;
177 +       u32 mask = BIT(d->width) - 1;
178 +
179 +       if (d->lpl)
180 +               mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift;
181 +
182 +       spin_lock_irqsave(&krait_clock_reg_lock, flags);
183 +       val = krait_get_l2_indirect_reg(d->offset);
184 +       val &= ~mask;
185 +       krait_set_l2_indirect_reg(d->offset, val);
186 +       spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
187 +
188 +       return 0;
189 +}
190 +
191 +static unsigned long
192 +krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
193 +{
194 +       struct krait_div2_clk *d = to_krait_div2_clk(hw);
195 +       u32 mask = BIT(d->width) - 1;
196 +       u32 div;
197 +
198 +       div = krait_get_l2_indirect_reg(d->offset);
199 +       div >>= d->shift;
200 +       div &= mask;
201 +       div = (div + 1) * 2;
202 +
203 +       return DIV_ROUND_UP(parent_rate, div);
204 +}
205 +
206 +const struct clk_ops krait_div2_clk_ops = {
207 +       .round_rate = krait_div2_round_rate,
208 +       .set_rate = krait_div2_set_rate,
209 +       .recalc_rate = krait_div2_recalc_rate,
210 +};
211 +EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
212 --- /dev/null
213 +++ b/drivers/clk/qcom/clk-krait.h
214 @@ -0,0 +1,49 @@
215 +/*
216 + * Copyright (c) 2013, The Linux Foundation. All rights reserved.
217 + *
218 + * This program is free software; you can redistribute it and/or modify
219 + * it under the terms of the GNU General Public License version 2 and
220 + * only version 2 as published by the Free Software Foundation.
221 + *
222 + * This program is distributed in the hope that it will be useful,
223 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
224 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
225 + * GNU General Public License for more details.
226 + */
227 +
228 +#ifndef __QCOM_CLK_KRAIT_H
229 +#define __QCOM_CLK_KRAIT_H
230 +
231 +#include <linux/clk-provider.h>
232 +
233 +struct krait_mux_clk {
234 +       unsigned int    *parent_map;
235 +       bool            has_safe_parent;
236 +       u8              safe_sel;
237 +       u32             offset;
238 +       u32             mask;
239 +       u32             shift;
240 +       u32             en_mask;
241 +       bool            lpl;
242 +
243 +       struct clk_hw   hw;
244 +};
245 +
246 +#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)
247 +
248 +extern const struct clk_ops krait_mux_clk_ops;
249 +
250 +struct krait_div2_clk {
251 +       u32             offset;
252 +       u8              width;
253 +       u32             shift;
254 +       bool            lpl;
255 +
256 +       struct clk_hw   hw;
257 +};
258 +
259 +#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw)
260 +
261 +extern const struct clk_ops krait_div2_clk_ops;
262 +
263 +#endif