1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Marvell PXA family clocks |
4 | * |
5 | * Copyright (C) 2014 Robert Jarzmik |
6 | * |
7 | * Common clock code for PXA clocks ("CKEN" type clocks + DT) |
8 | */ |
9 | #include <linux/clk.h> |
10 | #include <linux/clk-provider.h> |
11 | #include <linux/clkdev.h> |
12 | #include <linux/io.h> |
13 | #include <linux/of.h> |
14 | #include <linux/soc/pxa/smemc.h> |
15 | |
16 | #include <dt-bindings/clock/pxa-clock.h> |
17 | #include "clk-pxa.h" |
18 | |
19 | #define KHz 1000 |
20 | #define MHz (1000 * 1000) |
21 | |
22 | #define MDREFR_K0DB4 (1 << 29) /* SDCLK0 Divide by 4 Control/Status */ |
23 | #define MDREFR_K2FREE (1 << 25) /* SDRAM Free-Running Control */ |
24 | #define MDREFR_K1FREE (1 << 24) /* SDRAM Free-Running Control */ |
25 | #define MDREFR_K0FREE (1 << 23) /* SDRAM Free-Running Control */ |
26 | #define MDREFR_SLFRSH (1 << 22) /* SDRAM Self-Refresh Control/Status */ |
27 | #define MDREFR_APD (1 << 20) /* SDRAM/SSRAM Auto-Power-Down Enable */ |
28 | #define MDREFR_K2DB2 (1 << 19) /* SDCLK2 Divide by 2 Control/Status */ |
29 | #define MDREFR_K2RUN (1 << 18) /* SDCLK2 Run Control/Status */ |
30 | #define MDREFR_K1DB2 (1 << 17) /* SDCLK1 Divide by 2 Control/Status */ |
31 | #define MDREFR_K1RUN (1 << 16) /* SDCLK1 Run Control/Status */ |
32 | #define MDREFR_E1PIN (1 << 15) /* SDCKE1 Level Control/Status */ |
33 | #define MDREFR_K0DB2 (1 << 14) /* SDCLK0 Divide by 2 Control/Status */ |
34 | #define MDREFR_K0RUN (1 << 13) /* SDCLK0 Run Control/Status */ |
35 | #define MDREFR_E0PIN (1 << 12) /* SDCKE0 Level Control/Status */ |
36 | #define MDREFR_DB2_MASK (MDREFR_K2DB2 | MDREFR_K1DB2) |
37 | #define MDREFR_DRI_MASK 0xFFF |
38 | |
39 | static DEFINE_SPINLOCK(pxa_clk_lock); |
40 | |
41 | static struct clk *pxa_clocks[CLK_MAX]; |
42 | static struct clk_onecell_data onecell_data = { |
43 | .clks = pxa_clocks, |
44 | .clk_num = CLK_MAX, |
45 | }; |
46 | |
47 | struct pxa_clk { |
48 | struct clk_hw hw; |
49 | struct clk_fixed_factor lp; |
50 | struct clk_fixed_factor hp; |
51 | struct clk_gate gate; |
52 | bool (*is_in_low_power)(void); |
53 | }; |
54 | |
55 | #define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk, hw) |
56 | |
57 | static unsigned long cken_recalc_rate(struct clk_hw *hw, |
58 | unsigned long parent_rate) |
59 | { |
60 | struct pxa_clk *pclk = to_pxa_clk(hw); |
61 | struct clk_fixed_factor *fix; |
62 | |
63 | if (!pclk->is_in_low_power || pclk->is_in_low_power()) |
64 | fix = &pclk->lp; |
65 | else |
66 | fix = &pclk->hp; |
67 | __clk_hw_set_clk(dst: &fix->hw, src: hw); |
68 | return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate); |
69 | } |
70 | |
71 | static const struct clk_ops cken_rate_ops = { |
72 | .recalc_rate = cken_recalc_rate, |
73 | }; |
74 | |
75 | static u8 cken_get_parent(struct clk_hw *hw) |
76 | { |
77 | struct pxa_clk *pclk = to_pxa_clk(hw); |
78 | |
79 | if (!pclk->is_in_low_power) |
80 | return 0; |
81 | return pclk->is_in_low_power() ? 0 : 1; |
82 | } |
83 | |
84 | static const struct clk_ops cken_mux_ops = { |
85 | .determine_rate = clk_hw_determine_rate_no_reparent, |
86 | .get_parent = cken_get_parent, |
87 | .set_parent = dummy_clk_set_parent, |
88 | }; |
89 | |
90 | void __init clkdev_pxa_register(int ckid, const char *con_id, |
91 | const char *dev_id, struct clk *clk) |
92 | { |
93 | if (!IS_ERR(ptr: clk) && (ckid != CLK_NONE)) |
94 | pxa_clocks[ckid] = clk; |
95 | if (!IS_ERR(ptr: clk)) |
96 | clk_register_clkdev(clk, con_id, dev_id); |
97 | } |
98 | |
99 | int __init clk_pxa_cken_init(const struct desc_clk_cken *clks, |
100 | int nb_clks, void __iomem *clk_regs) |
101 | { |
102 | int i; |
103 | struct pxa_clk *pxa_clk; |
104 | struct clk *clk; |
105 | |
106 | for (i = 0; i < nb_clks; i++) { |
107 | pxa_clk = kzalloc(size: sizeof(*pxa_clk), GFP_KERNEL); |
108 | if (!pxa_clk) |
109 | return -ENOMEM; |
110 | pxa_clk->is_in_low_power = clks[i].is_in_low_power; |
111 | pxa_clk->lp = clks[i].lp; |
112 | pxa_clk->hp = clks[i].hp; |
113 | pxa_clk->gate = clks[i].gate; |
114 | pxa_clk->gate.reg = clk_regs + clks[i].cken_reg; |
115 | pxa_clk->gate.lock = &pxa_clk_lock; |
116 | clk = clk_register_composite(NULL, name: clks[i].name, |
117 | parent_names: clks[i].parent_names, num_parents: 2, |
118 | mux_hw: &pxa_clk->hw, mux_ops: &cken_mux_ops, |
119 | rate_hw: &pxa_clk->hw, rate_ops: &cken_rate_ops, |
120 | gate_hw: &pxa_clk->gate.hw, gate_ops: &clk_gate_ops, |
121 | flags: clks[i].flags); |
122 | clkdev_pxa_register(ckid: clks[i].ckid, con_id: clks[i].con_id, |
123 | dev_id: clks[i].dev_id, clk); |
124 | } |
125 | return 0; |
126 | } |
127 | |
128 | void __init clk_pxa_dt_common_init(struct device_node *np) |
129 | { |
130 | of_clk_add_provider(np, clk_src_get: of_clk_src_onecell_get, data: &onecell_data); |
131 | } |
132 | |
133 | void pxa2xx_core_turbo_switch(bool on) |
134 | { |
135 | unsigned long flags; |
136 | unsigned int unused, clkcfg; |
137 | |
138 | local_irq_save(flags); |
139 | |
140 | asm("mrc p14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); |
141 | clkcfg &= ~CLKCFG_TURBO & ~CLKCFG_HALFTURBO; |
142 | if (on) |
143 | clkcfg |= CLKCFG_TURBO; |
144 | clkcfg |= CLKCFG_FCS; |
145 | |
146 | asm volatile( |
147 | " b 2f\n" |
148 | " .align 5\n" |
149 | "1: mcr p14, 0, %1, c6, c0, 0\n" |
150 | " b 3f\n" |
151 | "2: b 1b\n" |
152 | "3: nop\n" |
153 | : "=&r" (unused) : "r" (clkcfg)); |
154 | |
155 | local_irq_restore(flags); |
156 | } |
157 | |
158 | void pxa2xx_cpll_change(struct pxa2xx_freq *freq, |
159 | u32 (*mdrefr_dri)(unsigned int), |
160 | void __iomem *cccr) |
161 | { |
162 | unsigned int clkcfg = freq->clkcfg; |
163 | unsigned int unused, preset_mdrefr, postset_mdrefr; |
164 | unsigned long flags; |
165 | void __iomem *mdrefr = pxa_smemc_get_mdrefr(); |
166 | |
167 | local_irq_save(flags); |
168 | |
169 | /* Calculate the next MDREFR. If we're slowing down the SDRAM clock |
170 | * we need to preset the smaller DRI before the change. If we're |
171 | * speeding up we need to set the larger DRI value after the change. |
172 | */ |
173 | preset_mdrefr = postset_mdrefr = readl(addr: mdrefr); |
174 | if ((preset_mdrefr & MDREFR_DRI_MASK) > mdrefr_dri(freq->membus_khz)) { |
175 | preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK); |
176 | preset_mdrefr |= mdrefr_dri(freq->membus_khz); |
177 | } |
178 | postset_mdrefr = |
179 | (postset_mdrefr & ~MDREFR_DRI_MASK) | |
180 | mdrefr_dri(freq->membus_khz); |
181 | |
182 | /* If we're dividing the memory clock by two for the SDRAM clock, this |
183 | * must be set prior to the change. Clearing the divide must be done |
184 | * after the change. |
185 | */ |
186 | if (freq->div2) { |
187 | preset_mdrefr |= MDREFR_DB2_MASK; |
188 | postset_mdrefr |= MDREFR_DB2_MASK; |
189 | } else { |
190 | postset_mdrefr &= ~MDREFR_DB2_MASK; |
191 | } |
192 | |
193 | /* Set new the CCCR and prepare CLKCFG */ |
194 | writel(val: freq->cccr, addr: cccr); |
195 | |
196 | asm volatile( |
197 | " ldr r4, [%1]\n" |
198 | " b 2f\n" |
199 | " .align 5\n" |
200 | "1: str %3, [%1] /* preset the MDREFR */\n" |
201 | " mcr p14, 0, %2, c6, c0, 0 /* set CLKCFG[FCS] */\n" |
202 | " str %4, [%1] /* postset the MDREFR */\n" |
203 | " b 3f\n" |
204 | "2: b 1b\n" |
205 | "3: nop\n" |
206 | : "=&r" (unused) |
207 | : "r" (mdrefr), "r" (clkcfg), "r" (preset_mdrefr), |
208 | "r" (postset_mdrefr) |
209 | : "r4" , "r5" ); |
210 | |
211 | local_irq_restore(flags); |
212 | } |
213 | |
214 | int pxa2xx_determine_rate(struct clk_rate_request *req, |
215 | struct pxa2xx_freq *freqs, int nb_freqs) |
216 | { |
217 | int i, closest_below = -1, closest_above = -1; |
218 | unsigned long rate; |
219 | |
220 | for (i = 0; i < nb_freqs; i++) { |
221 | rate = freqs[i].cpll; |
222 | if (rate == req->rate) |
223 | break; |
224 | if (rate < req->min_rate) |
225 | continue; |
226 | if (rate > req->max_rate) |
227 | continue; |
228 | if (rate <= req->rate) |
229 | closest_below = i; |
230 | if ((rate >= req->rate) && (closest_above == -1)) |
231 | closest_above = i; |
232 | } |
233 | |
234 | req->best_parent_hw = NULL; |
235 | |
236 | if (i < nb_freqs) { |
237 | rate = req->rate; |
238 | } else if (closest_below >= 0) { |
239 | rate = freqs[closest_below].cpll; |
240 | } else if (closest_above >= 0) { |
241 | rate = freqs[closest_above].cpll; |
242 | } else { |
243 | pr_debug("%s(rate=%lu) no match\n" , __func__, req->rate); |
244 | return -EINVAL; |
245 | } |
246 | |
247 | pr_debug("%s(rate=%lu) rate=%lu\n" , __func__, req->rate, rate); |
248 | req->rate = rate; |
249 | |
250 | return 0; |
251 | } |
252 | |