1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 #include <linux/kernel.h>
5 #include <linux/module.h>
6 #include <linux/init.h>
8 #include <linux/delay.h>
10 #include <linux/clk-provider.h>
11 #include <linux/spinlock.h>
13 #include <asm/krait-l2-accessors.h>
15 #include "clk-krait.h"
17 /* Secondary and primary muxes share the same cp15 register */
18 static DEFINE_SPINLOCK(krait_clock_reg_lock
);
21 #define SECCLKAGD BIT(4)
23 static void __krait_mux_set_sel(struct krait_mux_clk
*mux
, int sel
)
28 spin_lock_irqsave(&krait_clock_reg_lock
, flags
);
30 regval
= krait_get_l2_indirect_reg(mux
->offset
);
32 /* apq/ipq8064 Errata: disable sec_src clock gating during switch. */
33 if (mux
->disable_sec_src_gating
) {
35 krait_set_l2_indirect_reg(mux
->offset
, regval
);
38 regval
&= ~(mux
->mask
<< mux
->shift
);
39 regval
|= (sel
& mux
->mask
) << mux
->shift
;
41 regval
&= ~(mux
->mask
<< (mux
->shift
+ LPL_SHIFT
));
42 regval
|= (sel
& mux
->mask
) << (mux
->shift
+ LPL_SHIFT
);
44 krait_set_l2_indirect_reg(mux
->offset
, regval
);
46 /* apq/ipq8064 Errata: re-enabled sec_src clock gating. */
47 if (mux
->disable_sec_src_gating
) {
49 krait_set_l2_indirect_reg(mux
->offset
, regval
);
52 /* Wait for switch to complete. */
57 * Unlock now to make sure the mux register is not
58 * modified while switching to the new parent.
60 spin_unlock_irqrestore(&krait_clock_reg_lock
, flags
);
63 static int krait_mux_set_parent(struct clk_hw
*hw
, u8 index
)
65 struct krait_mux_clk
*mux
= to_krait_mux_clk(hw
);
68 sel
= clk_mux_index_to_val(mux
->parent_map
, 0, index
);
70 /* Don't touch mux if CPU is off as it won't work */
71 if (__clk_is_enabled(hw
->clk
))
72 __krait_mux_set_sel(mux
, sel
);
79 static u8
krait_mux_get_parent(struct clk_hw
*hw
)
81 struct krait_mux_clk
*mux
= to_krait_mux_clk(hw
);
84 sel
= krait_get_l2_indirect_reg(mux
->offset
);
89 return clk_mux_val_to_index(hw
, mux
->parent_map
, 0, sel
);
92 const struct clk_ops krait_mux_clk_ops
= {
93 .set_parent
= krait_mux_set_parent
,
94 .get_parent
= krait_mux_get_parent
,
95 .determine_rate
= __clk_mux_determine_rate_closest
,
97 EXPORT_SYMBOL_GPL(krait_mux_clk_ops
);
99 /* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
100 static int krait_div2_determine_rate(struct clk_hw
*hw
, struct clk_rate_request
*req
)
102 req
->best_parent_rate
= clk_hw_round_rate(clk_hw_get_parent(hw
), req
->rate
* 2);
103 req
->rate
= DIV_ROUND_UP(req
->best_parent_rate
, 2);
107 static int krait_div2_set_rate(struct clk_hw
*hw
, unsigned long rate
,
108 unsigned long parent_rate
)
110 struct krait_div2_clk
*d
= to_krait_div2_clk(hw
);
113 u32 mask
= BIT(d
->width
) - 1;
116 mask
= mask
<< (d
->shift
+ LPL_SHIFT
) | mask
<< d
->shift
;
120 spin_lock_irqsave(&krait_clock_reg_lock
, flags
);
121 val
= krait_get_l2_indirect_reg(d
->offset
);
123 krait_set_l2_indirect_reg(d
->offset
, val
);
124 spin_unlock_irqrestore(&krait_clock_reg_lock
, flags
);
130 krait_div2_recalc_rate(struct clk_hw
*hw
, unsigned long parent_rate
)
132 struct krait_div2_clk
*d
= to_krait_div2_clk(hw
);
133 u32 mask
= BIT(d
->width
) - 1;
136 div
= krait_get_l2_indirect_reg(d
->offset
);
141 return DIV_ROUND_UP(parent_rate
, div
);
144 const struct clk_ops krait_div2_clk_ops
= {
145 .determine_rate
= krait_div2_determine_rate
,
146 .set_rate
= krait_div2_set_rate
,
147 .recalc_rate
= krait_div2_recalc_rate
,
149 EXPORT_SYMBOL_GPL(krait_div2_clk_ops
);