2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 * Author: Thomas Abraham <thomas.ab@samsung.com>
5 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
6 * Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This file contains the utility function to register CPU clock for Samsung
13 * Exynos platforms. A CPU clock is defined as a clock supplied to a CPU or a
14 * group of CPUs. The CPU clock is typically derived from a hierarchy of clock
15 * blocks which includes mux and divider blocks. There are a number of other
16 * auxiliary clocks supplied to the CPU domain such as the debug blocks and AXI
17 * clock for CPU domain. The rates of these auxiliary clocks are related to the
18 * CPU clock rate and this relation is usually specified in the hardware manual
19 * of the SoC or supplied after the SoC characterization.
21 * The below implementation of the CPU clock allows the rate changes of the CPU
22 * clock and the corresponding rate changes of the auxillary clocks of the CPU
23 * domain. The platform clock driver provides a clock register configuration
24 * for each configurable rate which is then used to program the clock hardware
25 * registers to acheive a fast co-oridinated rate change for all the CPU domain
28 * On a rate change request for the CPU clock, the rate change is propagated
29 * upto the PLL supplying the clock to the CPU domain clock blocks. While the
30 * CPU domain PLL is reconfigured, the CPU domain clocks are driven using an
31 * alternate clock source. If required, the alternate clock source is divided
32 * down in order to keep the output clock rate within the previous OPP limits.
35 #include <linux/errno.h>
36 #include <linux/slab.h>
37 #include <linux/clk.h>
38 #include <linux/clk-provider.h>
41 #define E4210_SRC_CPU 0x0
42 #define E4210_STAT_CPU 0x200
43 #define E4210_DIV_CPU0 0x300
44 #define E4210_DIV_CPU1 0x304
45 #define E4210_DIV_STAT_CPU0 0x400
46 #define E4210_DIV_STAT_CPU1 0x404
48 #define E4210_DIV0_RATIO0_MASK 0x7
49 #define E4210_DIV1_HPM_MASK (0x7 << 4)
50 #define E4210_DIV1_COPY_MASK (0x7 << 0)
51 #define E4210_MUX_HPM_MASK (1 << 20)
52 #define E4210_DIV0_ATB_SHIFT 16
53 #define E4210_DIV0_ATB_MASK (DIV_MASK << E4210_DIV0_ATB_SHIFT)
57 #define DIV_MASK_ALL 0xffffffff
61 * Helper function to wait until divider(s) have stabilized after the divider
64 static void wait_until_divider_stable(void __iomem
*div_reg
, unsigned long mask
)
66 unsigned long timeout
= jiffies
+ msecs_to_jiffies(10);
69 if (!(readl(div_reg
) & mask
))
71 } while (time_before(jiffies
, timeout
));
73 if (!(readl(div_reg
) & mask
))
76 pr_err("%s: timeout in divider stablization\n", __func__
);
80 * Helper function to wait until mux has stabilized after the mux selection
83 static void wait_until_mux_stable(void __iomem
*mux_reg
, u32 mux_pos
,
84 unsigned long mux_value
)
86 unsigned long timeout
= jiffies
+ msecs_to_jiffies(10);
89 if (((readl(mux_reg
) >> mux_pos
) & MUX_MASK
) == mux_value
)
91 } while (time_before(jiffies
, timeout
));
93 if (((readl(mux_reg
) >> mux_pos
) & MUX_MASK
) == mux_value
)
96 pr_err("%s: re-parenting mux timed-out\n", __func__
);
99 /* common round rate callback useable for all types of CPU clocks */
100 static long exynos_cpuclk_round_rate(struct clk_hw
*hw
,
101 unsigned long drate
, unsigned long *prate
)
103 struct clk_hw
*parent
= clk_hw_get_parent(hw
);
104 *prate
= clk_hw_round_rate(parent
, drate
);
108 /* common recalc rate callback useable for all types of CPU clocks */
109 static unsigned long exynos_cpuclk_recalc_rate(struct clk_hw
*hw
,
110 unsigned long parent_rate
)
113 * The CPU clock output (armclk) rate is the same as its parent
114 * rate. Although there exist certain dividers inside the CPU
115 * clock block that could be used to divide the parent clock,
116 * the driver does not make use of them currently, except during
117 * frequency transitions.
122 static const struct clk_ops exynos_cpuclk_clk_ops
= {
123 .recalc_rate
= exynos_cpuclk_recalc_rate
,
124 .round_rate
= exynos_cpuclk_round_rate
,
128 * Helper function to set the 'safe' dividers for the CPU clock. The parameters
129 * div and mask contain the divider value and the register bit mask of the
130 * dividers to be programmed.
132 static void exynos_set_safe_div(void __iomem
*base
, unsigned long div
,
137 div0
= readl(base
+ E4210_DIV_CPU0
);
138 div0
= (div0
& ~mask
) | (div
& mask
);
139 writel(div0
, base
+ E4210_DIV_CPU0
);
140 wait_until_divider_stable(base
+ E4210_DIV_STAT_CPU0
, mask
);
143 /* handler for pre-rate change notification from parent clock */
144 static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data
*ndata
,
145 struct exynos_cpuclk
*cpuclk
, void __iomem
*base
)
147 const struct exynos_cpuclk_cfg_data
*cfg_data
= cpuclk
->cfg
;
148 unsigned long alt_prate
= clk_get_rate(cpuclk
->alt_parent
);
149 unsigned long alt_div
= 0, alt_div_mask
= DIV_MASK
;
150 unsigned long div0
, div1
= 0, mux_reg
;
152 /* find out the divider values to use for clock data */
153 while ((cfg_data
->prate
* 1000) != ndata
->new_rate
) {
154 if (cfg_data
->prate
== 0)
159 spin_lock(cpuclk
->lock
);
162 * For the selected PLL clock frequency, get the pre-defined divider
163 * values. If the clock for sclk_hpm is not sourced from apll, then
164 * the values for DIV_COPY and DIV_HPM dividers need not be set.
166 div0
= cfg_data
->div0
;
167 if (test_bit(CLK_CPU_HAS_DIV1
, &cpuclk
->flags
)) {
168 div1
= cfg_data
->div1
;
169 if (readl(base
+ E4210_SRC_CPU
) & E4210_MUX_HPM_MASK
)
170 div1
= readl(base
+ E4210_DIV_CPU1
) &
171 (E4210_DIV1_HPM_MASK
| E4210_DIV1_COPY_MASK
);
175 * If the old parent clock speed is less than the clock speed of
176 * the alternate parent, then it should be ensured that at no point
177 * the armclk speed is more than the old_prate until the dividers are
178 * set. Also workaround the issue of the dividers being set to lower
179 * values before the parent clock speed is set to new lower speed
180 * (this can result in too high speed of armclk output clocks).
182 if (alt_prate
> ndata
->old_rate
|| ndata
->old_rate
> ndata
->new_rate
) {
183 unsigned long tmp_rate
= min(ndata
->old_rate
, ndata
->new_rate
);
185 alt_div
= DIV_ROUND_UP(alt_prate
, tmp_rate
) - 1;
186 WARN_ON(alt_div
>= MAX_DIV
);
188 if (test_bit(CLK_CPU_NEEDS_DEBUG_ALT_DIV
, &cpuclk
->flags
)) {
190 * In Exynos4210, ATB clock parent is also mout_core. So
191 * ATB clock also needs to be mantained at safe speed.
193 alt_div
|= E4210_DIV0_ATB_MASK
;
194 alt_div_mask
|= E4210_DIV0_ATB_MASK
;
196 exynos_set_safe_div(base
, alt_div
, alt_div_mask
);
200 /* select sclk_mpll as the alternate parent */
201 mux_reg
= readl(base
+ E4210_SRC_CPU
);
202 writel(mux_reg
| (1 << 16), base
+ E4210_SRC_CPU
);
203 wait_until_mux_stable(base
+ E4210_STAT_CPU
, 16, 2);
205 /* alternate parent is active now. set the dividers */
206 writel(div0
, base
+ E4210_DIV_CPU0
);
207 wait_until_divider_stable(base
+ E4210_DIV_STAT_CPU0
, DIV_MASK_ALL
);
209 if (test_bit(CLK_CPU_HAS_DIV1
, &cpuclk
->flags
)) {
210 writel(div1
, base
+ E4210_DIV_CPU1
);
211 wait_until_divider_stable(base
+ E4210_DIV_STAT_CPU1
,
215 spin_unlock(cpuclk
->lock
);
219 /* handler for post-rate change notification from parent clock */
220 static int exynos_cpuclk_post_rate_change(struct clk_notifier_data
*ndata
,
221 struct exynos_cpuclk
*cpuclk
, void __iomem
*base
)
223 const struct exynos_cpuclk_cfg_data
*cfg_data
= cpuclk
->cfg
;
224 unsigned long div
= 0, div_mask
= DIV_MASK
;
225 unsigned long mux_reg
;
227 /* find out the divider values to use for clock data */
228 if (test_bit(CLK_CPU_NEEDS_DEBUG_ALT_DIV
, &cpuclk
->flags
)) {
229 while ((cfg_data
->prate
* 1000) != ndata
->new_rate
) {
230 if (cfg_data
->prate
== 0)
236 spin_lock(cpuclk
->lock
);
238 /* select mout_apll as the alternate parent */
239 mux_reg
= readl(base
+ E4210_SRC_CPU
);
240 writel(mux_reg
& ~(1 << 16), base
+ E4210_SRC_CPU
);
241 wait_until_mux_stable(base
+ E4210_STAT_CPU
, 16, 1);
243 if (test_bit(CLK_CPU_NEEDS_DEBUG_ALT_DIV
, &cpuclk
->flags
)) {
244 div
|= (cfg_data
->div0
& E4210_DIV0_ATB_MASK
);
245 div_mask
|= E4210_DIV0_ATB_MASK
;
248 exynos_set_safe_div(base
, div
, div_mask
);
249 spin_unlock(cpuclk
->lock
);
254 * This notifier function is called for the pre-rate and post-rate change
255 * notifications of the parent clock of cpuclk.
257 static int exynos_cpuclk_notifier_cb(struct notifier_block
*nb
,
258 unsigned long event
, void *data
)
260 struct clk_notifier_data
*ndata
= data
;
261 struct exynos_cpuclk
*cpuclk
;
265 cpuclk
= container_of(nb
, struct exynos_cpuclk
, clk_nb
);
266 base
= cpuclk
->ctrl_base
;
268 if (event
== PRE_RATE_CHANGE
)
269 err
= exynos_cpuclk_pre_rate_change(ndata
, cpuclk
, base
);
270 else if (event
== POST_RATE_CHANGE
)
271 err
= exynos_cpuclk_post_rate_change(ndata
, cpuclk
, base
);
273 return notifier_from_errno(err
);
276 /* helper function to register a CPU clock */
277 int __init
exynos_register_cpu_clock(struct samsung_clk_provider
*ctx
,
278 unsigned int lookup_id
, const char *name
, const char *parent
,
279 const char *alt_parent
, unsigned long offset
,
280 const struct exynos_cpuclk_cfg_data
*cfg
,
281 unsigned long num_cfgs
, unsigned long flags
)
283 struct exynos_cpuclk
*cpuclk
;
284 struct clk_init_data init
;
288 cpuclk
= kzalloc(sizeof(*cpuclk
), GFP_KERNEL
);
293 init
.flags
= CLK_SET_RATE_PARENT
;
294 init
.parent_names
= &parent
;
295 init
.num_parents
= 1;
296 init
.ops
= &exynos_cpuclk_clk_ops
;
298 cpuclk
->hw
.init
= &init
;
299 cpuclk
->ctrl_base
= ctx
->reg_base
+ offset
;
300 cpuclk
->lock
= &ctx
->lock
;
301 cpuclk
->flags
= flags
;
302 cpuclk
->clk_nb
.notifier_call
= exynos_cpuclk_notifier_cb
;
304 cpuclk
->alt_parent
= __clk_lookup(alt_parent
);
305 if (!cpuclk
->alt_parent
) {
306 pr_err("%s: could not lookup alternate parent %s\n",
307 __func__
, alt_parent
);
312 clk
= __clk_lookup(parent
);
314 pr_err("%s: could not lookup parent clock %s\n",
320 ret
= clk_notifier_register(clk
, &cpuclk
->clk_nb
);
322 pr_err("%s: failed to register clock notifier for %s\n",
327 cpuclk
->cfg
= kmemdup(cfg
, sizeof(*cfg
) * num_cfgs
, GFP_KERNEL
);
329 pr_err("%s: could not allocate memory for cpuclk data\n",
332 goto unregister_clk_nb
;
335 clk
= clk_register(NULL
, &cpuclk
->hw
);
337 pr_err("%s: could not register cpuclk %s\n", __func__
, name
);
339 goto free_cpuclk_data
;
342 samsung_clk_add_lookup(ctx
, clk
, lookup_id
);
348 clk_notifier_unregister(__clk_lookup(parent
), &cpuclk
->clk_nb
);