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>
37 #include <linux/slab.h>
38 #include <linux/clk.h>
39 #include <linux/clk-provider.h>
42 #define E4210_SRC_CPU 0x0
43 #define E4210_STAT_CPU 0x200
44 #define E4210_DIV_CPU0 0x300
45 #define E4210_DIV_CPU1 0x304
46 #define E4210_DIV_STAT_CPU0 0x400
47 #define E4210_DIV_STAT_CPU1 0x404
49 #define E5433_MUX_SEL2 0x008
50 #define E5433_MUX_STAT2 0x208
51 #define E5433_DIV_CPU0 0x400
52 #define E5433_DIV_CPU1 0x404
53 #define E5433_DIV_STAT_CPU0 0x500
54 #define E5433_DIV_STAT_CPU1 0x504
56 #define E4210_DIV0_RATIO0_MASK 0x7
57 #define E4210_DIV1_HPM_MASK (0x7 << 4)
58 #define E4210_DIV1_COPY_MASK (0x7 << 0)
59 #define E4210_MUX_HPM_MASK (1 << 20)
60 #define E4210_DIV0_ATB_SHIFT 16
61 #define E4210_DIV0_ATB_MASK (DIV_MASK << E4210_DIV0_ATB_SHIFT)
65 #define DIV_MASK_ALL 0xffffffff
69 * Helper function to wait until divider(s) have stabilized after the divider
72 static void wait_until_divider_stable(void __iomem
*div_reg
, unsigned long mask
)
74 unsigned long timeout
= jiffies
+ msecs_to_jiffies(10);
77 if (!(readl(div_reg
) & mask
))
79 } while (time_before(jiffies
, timeout
));
81 if (!(readl(div_reg
) & mask
))
84 pr_err("%s: timeout in divider stablization\n", __func__
);
88 * Helper function to wait until mux has stabilized after the mux selection
91 static void wait_until_mux_stable(void __iomem
*mux_reg
, u32 mux_pos
,
92 unsigned long mux_value
)
94 unsigned long timeout
= jiffies
+ msecs_to_jiffies(10);
97 if (((readl(mux_reg
) >> mux_pos
) & MUX_MASK
) == mux_value
)
99 } while (time_before(jiffies
, timeout
));
101 if (((readl(mux_reg
) >> mux_pos
) & MUX_MASK
) == mux_value
)
104 pr_err("%s: re-parenting mux timed-out\n", __func__
);
107 /* common round rate callback useable for all types of CPU clocks */
108 static long exynos_cpuclk_round_rate(struct clk_hw
*hw
,
109 unsigned long drate
, unsigned long *prate
)
111 struct clk_hw
*parent
= clk_hw_get_parent(hw
);
112 *prate
= clk_hw_round_rate(parent
, drate
);
116 /* common recalc rate callback useable for all types of CPU clocks */
117 static unsigned long exynos_cpuclk_recalc_rate(struct clk_hw
*hw
,
118 unsigned long parent_rate
)
121 * The CPU clock output (armclk) rate is the same as its parent
122 * rate. Although there exist certain dividers inside the CPU
123 * clock block that could be used to divide the parent clock,
124 * the driver does not make use of them currently, except during
125 * frequency transitions.
130 static const struct clk_ops exynos_cpuclk_clk_ops
= {
131 .recalc_rate
= exynos_cpuclk_recalc_rate
,
132 .round_rate
= exynos_cpuclk_round_rate
,
136 * Helper function to set the 'safe' dividers for the CPU clock. The parameters
137 * div and mask contain the divider value and the register bit mask of the
138 * dividers to be programmed.
140 static void exynos_set_safe_div(void __iomem
*base
, unsigned long div
,
145 div0
= readl(base
+ E4210_DIV_CPU0
);
146 div0
= (div0
& ~mask
) | (div
& mask
);
147 writel(div0
, base
+ E4210_DIV_CPU0
);
148 wait_until_divider_stable(base
+ E4210_DIV_STAT_CPU0
, mask
);
151 /* handler for pre-rate change notification from parent clock */
152 static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data
*ndata
,
153 struct exynos_cpuclk
*cpuclk
, void __iomem
*base
)
155 const struct exynos_cpuclk_cfg_data
*cfg_data
= cpuclk
->cfg
;
156 unsigned long alt_prate
= clk_hw_get_rate(cpuclk
->alt_parent
);
157 unsigned long alt_div
= 0, alt_div_mask
= DIV_MASK
;
158 unsigned long div0
, div1
= 0, mux_reg
;
161 /* find out the divider values to use for clock data */
162 while ((cfg_data
->prate
* 1000) != ndata
->new_rate
) {
163 if (cfg_data
->prate
== 0)
168 spin_lock_irqsave(cpuclk
->lock
, flags
);
171 * For the selected PLL clock frequency, get the pre-defined divider
172 * values. If the clock for sclk_hpm is not sourced from apll, then
173 * the values for DIV_COPY and DIV_HPM dividers need not be set.
175 div0
= cfg_data
->div0
;
176 if (cpuclk
->flags
& CLK_CPU_HAS_DIV1
) {
177 div1
= cfg_data
->div1
;
178 if (readl(base
+ E4210_SRC_CPU
) & E4210_MUX_HPM_MASK
)
179 div1
= readl(base
+ E4210_DIV_CPU1
) &
180 (E4210_DIV1_HPM_MASK
| E4210_DIV1_COPY_MASK
);
184 * If the old parent clock speed is less than the clock speed of
185 * the alternate parent, then it should be ensured that at no point
186 * the armclk speed is more than the old_prate until the dividers are
187 * set. Also workaround the issue of the dividers being set to lower
188 * values before the parent clock speed is set to new lower speed
189 * (this can result in too high speed of armclk output clocks).
191 if (alt_prate
> ndata
->old_rate
|| ndata
->old_rate
> ndata
->new_rate
) {
192 unsigned long tmp_rate
= min(ndata
->old_rate
, ndata
->new_rate
);
194 alt_div
= DIV_ROUND_UP(alt_prate
, tmp_rate
) - 1;
195 WARN_ON(alt_div
>= MAX_DIV
);
197 if (cpuclk
->flags
& CLK_CPU_NEEDS_DEBUG_ALT_DIV
) {
199 * In Exynos4210, ATB clock parent is also mout_core. So
200 * ATB clock also needs to be mantained at safe speed.
202 alt_div
|= E4210_DIV0_ATB_MASK
;
203 alt_div_mask
|= E4210_DIV0_ATB_MASK
;
205 exynos_set_safe_div(base
, alt_div
, alt_div_mask
);
209 /* select sclk_mpll as the alternate parent */
210 mux_reg
= readl(base
+ E4210_SRC_CPU
);
211 writel(mux_reg
| (1 << 16), base
+ E4210_SRC_CPU
);
212 wait_until_mux_stable(base
+ E4210_STAT_CPU
, 16, 2);
214 /* alternate parent is active now. set the dividers */
215 writel(div0
, base
+ E4210_DIV_CPU0
);
216 wait_until_divider_stable(base
+ E4210_DIV_STAT_CPU0
, DIV_MASK_ALL
);
218 if (cpuclk
->flags
& CLK_CPU_HAS_DIV1
) {
219 writel(div1
, base
+ E4210_DIV_CPU1
);
220 wait_until_divider_stable(base
+ E4210_DIV_STAT_CPU1
,
224 spin_unlock_irqrestore(cpuclk
->lock
, flags
);
228 /* handler for post-rate change notification from parent clock */
229 static int exynos_cpuclk_post_rate_change(struct clk_notifier_data
*ndata
,
230 struct exynos_cpuclk
*cpuclk
, void __iomem
*base
)
232 const struct exynos_cpuclk_cfg_data
*cfg_data
= cpuclk
->cfg
;
233 unsigned long div
= 0, div_mask
= DIV_MASK
;
234 unsigned long mux_reg
;
237 /* find out the divider values to use for clock data */
238 if (cpuclk
->flags
& CLK_CPU_NEEDS_DEBUG_ALT_DIV
) {
239 while ((cfg_data
->prate
* 1000) != ndata
->new_rate
) {
240 if (cfg_data
->prate
== 0)
246 spin_lock_irqsave(cpuclk
->lock
, flags
);
248 /* select mout_apll as the alternate parent */
249 mux_reg
= readl(base
+ E4210_SRC_CPU
);
250 writel(mux_reg
& ~(1 << 16), base
+ E4210_SRC_CPU
);
251 wait_until_mux_stable(base
+ E4210_STAT_CPU
, 16, 1);
253 if (cpuclk
->flags
& CLK_CPU_NEEDS_DEBUG_ALT_DIV
) {
254 div
|= (cfg_data
->div0
& E4210_DIV0_ATB_MASK
);
255 div_mask
|= E4210_DIV0_ATB_MASK
;
258 exynos_set_safe_div(base
, div
, div_mask
);
259 spin_unlock_irqrestore(cpuclk
->lock
, flags
);
264 * Helper function to set the 'safe' dividers for the CPU clock. The parameters
265 * div and mask contain the divider value and the register bit mask of the
266 * dividers to be programmed.
268 static void exynos5433_set_safe_div(void __iomem
*base
, unsigned long div
,
273 div0
= readl(base
+ E5433_DIV_CPU0
);
274 div0
= (div0
& ~mask
) | (div
& mask
);
275 writel(div0
, base
+ E5433_DIV_CPU0
);
276 wait_until_divider_stable(base
+ E5433_DIV_STAT_CPU0
, mask
);
279 /* handler for pre-rate change notification from parent clock */
280 static int exynos5433_cpuclk_pre_rate_change(struct clk_notifier_data
*ndata
,
281 struct exynos_cpuclk
*cpuclk
, void __iomem
*base
)
283 const struct exynos_cpuclk_cfg_data
*cfg_data
= cpuclk
->cfg
;
284 unsigned long alt_prate
= clk_hw_get_rate(cpuclk
->alt_parent
);
285 unsigned long alt_div
= 0, alt_div_mask
= DIV_MASK
;
286 unsigned long div0
, div1
= 0, mux_reg
;
289 /* find out the divider values to use for clock data */
290 while ((cfg_data
->prate
* 1000) != ndata
->new_rate
) {
291 if (cfg_data
->prate
== 0)
296 spin_lock_irqsave(cpuclk
->lock
, flags
);
299 * For the selected PLL clock frequency, get the pre-defined divider
302 div0
= cfg_data
->div0
;
303 div1
= cfg_data
->div1
;
306 * If the old parent clock speed is less than the clock speed of
307 * the alternate parent, then it should be ensured that at no point
308 * the armclk speed is more than the old_prate until the dividers are
309 * set. Also workaround the issue of the dividers being set to lower
310 * values before the parent clock speed is set to new lower speed
311 * (this can result in too high speed of armclk output clocks).
313 if (alt_prate
> ndata
->old_rate
|| ndata
->old_rate
> ndata
->new_rate
) {
314 unsigned long tmp_rate
= min(ndata
->old_rate
, ndata
->new_rate
);
316 alt_div
= DIV_ROUND_UP(alt_prate
, tmp_rate
) - 1;
317 WARN_ON(alt_div
>= MAX_DIV
);
319 exynos5433_set_safe_div(base
, alt_div
, alt_div_mask
);
323 /* select the alternate parent */
324 mux_reg
= readl(base
+ E5433_MUX_SEL2
);
325 writel(mux_reg
| 1, base
+ E5433_MUX_SEL2
);
326 wait_until_mux_stable(base
+ E5433_MUX_STAT2
, 0, 2);
328 /* alternate parent is active now. set the dividers */
329 writel(div0
, base
+ E5433_DIV_CPU0
);
330 wait_until_divider_stable(base
+ E5433_DIV_STAT_CPU0
, DIV_MASK_ALL
);
332 writel(div1
, base
+ E5433_DIV_CPU1
);
333 wait_until_divider_stable(base
+ E5433_DIV_STAT_CPU1
, DIV_MASK_ALL
);
335 spin_unlock_irqrestore(cpuclk
->lock
, flags
);
339 /* handler for post-rate change notification from parent clock */
340 static int exynos5433_cpuclk_post_rate_change(struct clk_notifier_data
*ndata
,
341 struct exynos_cpuclk
*cpuclk
, void __iomem
*base
)
343 unsigned long div
= 0, div_mask
= DIV_MASK
;
344 unsigned long mux_reg
;
347 spin_lock_irqsave(cpuclk
->lock
, flags
);
349 /* select apll as the alternate parent */
350 mux_reg
= readl(base
+ E5433_MUX_SEL2
);
351 writel(mux_reg
& ~1, base
+ E5433_MUX_SEL2
);
352 wait_until_mux_stable(base
+ E5433_MUX_STAT2
, 0, 1);
354 exynos5433_set_safe_div(base
, div
, div_mask
);
355 spin_unlock_irqrestore(cpuclk
->lock
, flags
);
360 * This notifier function is called for the pre-rate and post-rate change
361 * notifications of the parent clock of cpuclk.
363 static int exynos_cpuclk_notifier_cb(struct notifier_block
*nb
,
364 unsigned long event
, void *data
)
366 struct clk_notifier_data
*ndata
= data
;
367 struct exynos_cpuclk
*cpuclk
;
371 cpuclk
= container_of(nb
, struct exynos_cpuclk
, clk_nb
);
372 base
= cpuclk
->ctrl_base
;
374 if (event
== PRE_RATE_CHANGE
)
375 err
= exynos_cpuclk_pre_rate_change(ndata
, cpuclk
, base
);
376 else if (event
== POST_RATE_CHANGE
)
377 err
= exynos_cpuclk_post_rate_change(ndata
, cpuclk
, base
);
379 return notifier_from_errno(err
);
383 * This notifier function is called for the pre-rate and post-rate change
384 * notifications of the parent clock of cpuclk.
386 static int exynos5433_cpuclk_notifier_cb(struct notifier_block
*nb
,
387 unsigned long event
, void *data
)
389 struct clk_notifier_data
*ndata
= data
;
390 struct exynos_cpuclk
*cpuclk
;
394 cpuclk
= container_of(nb
, struct exynos_cpuclk
, clk_nb
);
395 base
= cpuclk
->ctrl_base
;
397 if (event
== PRE_RATE_CHANGE
)
398 err
= exynos5433_cpuclk_pre_rate_change(ndata
, cpuclk
, base
);
399 else if (event
== POST_RATE_CHANGE
)
400 err
= exynos5433_cpuclk_post_rate_change(ndata
, cpuclk
, base
);
402 return notifier_from_errno(err
);
405 /* helper function to register a CPU clock */
406 int __init
exynos_register_cpu_clock(struct samsung_clk_provider
*ctx
,
407 unsigned int lookup_id
, const char *name
, const char *parent
,
408 const char *alt_parent
, unsigned long offset
,
409 const struct exynos_cpuclk_cfg_data
*cfg
,
410 unsigned long num_cfgs
, unsigned long flags
)
412 struct exynos_cpuclk
*cpuclk
;
413 struct clk_init_data init
;
414 struct clk
*parent_clk
;
417 cpuclk
= kzalloc(sizeof(*cpuclk
), GFP_KERNEL
);
422 init
.flags
= CLK_SET_RATE_PARENT
;
423 init
.parent_names
= &parent
;
424 init
.num_parents
= 1;
425 init
.ops
= &exynos_cpuclk_clk_ops
;
427 cpuclk
->hw
.init
= &init
;
428 cpuclk
->ctrl_base
= ctx
->reg_base
+ offset
;
429 cpuclk
->lock
= &ctx
->lock
;
430 cpuclk
->flags
= flags
;
431 if (flags
& CLK_CPU_HAS_E5433_REGS_LAYOUT
)
432 cpuclk
->clk_nb
.notifier_call
= exynos5433_cpuclk_notifier_cb
;
434 cpuclk
->clk_nb
.notifier_call
= exynos_cpuclk_notifier_cb
;
436 cpuclk
->alt_parent
= __clk_get_hw(__clk_lookup(alt_parent
));
437 if (!cpuclk
->alt_parent
) {
438 pr_err("%s: could not lookup alternate parent %s\n",
439 __func__
, alt_parent
);
444 parent_clk
= __clk_lookup(parent
);
446 pr_err("%s: could not lookup parent clock %s\n",
452 ret
= clk_notifier_register(parent_clk
, &cpuclk
->clk_nb
);
454 pr_err("%s: failed to register clock notifier for %s\n",
459 cpuclk
->cfg
= kmemdup(cfg
, sizeof(*cfg
) * num_cfgs
, GFP_KERNEL
);
462 goto unregister_clk_nb
;
465 ret
= clk_hw_register(NULL
, &cpuclk
->hw
);
467 pr_err("%s: could not register cpuclk %s\n", __func__
, name
);
468 goto free_cpuclk_data
;
471 samsung_clk_add_lookup(ctx
, &cpuclk
->hw
, lookup_id
);
477 clk_notifier_unregister(parent_clk
, &cpuclk
->clk_nb
);