sifive-prci.c (efc91ae43c8d4bbf64e4b9a28113b24a74ffd58d) sifive-prci.c (732374a0b440d9a79c8412f318a25cd37ba6f4e2)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2020 SiFive, Inc.
4 * Copyright (C) 2020 Zong Li
5 */
6
7#include <linux/clkdev.h>
8#include <linux/delay.h>

--- 99 unchanged lines hidden (view full) ---

108
109 /* external feedback mode not supported */
110 r |= PRCI_COREPLLCFG0_FSE_MASK;
111
112 return r;
113}
114
115/**
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2020 SiFive, Inc.
4 * Copyright (C) 2020 Zong Li
5 */
6
7#include <linux/clkdev.h>
8#include <linux/delay.h>

--- 99 unchanged lines hidden (view full) ---

108
109 /* external feedback mode not supported */
110 r |= PRCI_COREPLLCFG0_FSE_MASK;
111
112 return r;
113}
114
115/**
116 * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI
116 * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI
117 * @pd: PRCI context
118 * @pwd: PRCI WRPLL metadata
119 *
120 * Read the current configuration of the PLL identified by @pwd from
121 * the PRCI identified by @pd, and store it into the local configuration
122 * cache in @pwd.
123 *
124 * Context: Any context. Caller must prevent the records pointed to by
125 * @pd and @pwd from changing during execution.
126 */
117 * @pd: PRCI context
118 * @pwd: PRCI WRPLL metadata
119 *
120 * Read the current configuration of the PLL identified by @pwd from
121 * the PRCI identified by @pd, and store it into the local configuration
122 * cache in @pwd.
123 *
124 * Context: Any context. Caller must prevent the records pointed to by
125 * @pd and @pwd from changing during execution.
126 */
127static void __prci_wrpll_read_cfg(struct __prci_data *pd,
128 struct __prci_wrpll_data *pwd)
127static void __prci_wrpll_read_cfg0(struct __prci_data *pd,
128 struct __prci_wrpll_data *pwd)
129{
130 __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
131}
132
133/**
129{
130 __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
131}
132
133/**
134 * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI
134 * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI
135 * @pd: PRCI context
136 * @pwd: PRCI WRPLL metadata
137 * @c: WRPLL configuration record to write
138 *
139 * Write the WRPLL configuration described by @c into the WRPLL
140 * configuration register identified by @pwd in the PRCI instance
141 * described by @c. Make a cached copy of the WRPLL's current
142 * configuration so it can be used by other code.
143 *
144 * Context: Any context. Caller must prevent the records pointed to by
145 * @pd and @pwd from changing during execution.
146 */
135 * @pd: PRCI context
136 * @pwd: PRCI WRPLL metadata
137 * @c: WRPLL configuration record to write
138 *
139 * Write the WRPLL configuration described by @c into the WRPLL
140 * configuration register identified by @pwd in the PRCI instance
141 * described by @c. Make a cached copy of the WRPLL's current
142 * configuration so it can be used by other code.
143 *
144 * Context: Any context. Caller must prevent the records pointed to by
145 * @pd and @pwd from changing during execution.
146 */
147static void __prci_wrpll_write_cfg(struct __prci_data *pd,
148 struct __prci_wrpll_data *pwd,
149 struct wrpll_cfg *c)
147static void __prci_wrpll_write_cfg0(struct __prci_data *pd,
148 struct __prci_wrpll_data *pwd,
149 struct wrpll_cfg *c)
150{
151 __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
152
153 memcpy(&pwd->c, c, sizeof(*c));
154}
155
150{
151 __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
152
153 memcpy(&pwd->c, c, sizeof(*c));
154}
155
156/**
157 * __prci_wrpll_write_cfg1() - write Clock enable/disable configuration
158 * into the PRCI
159 * @pd: PRCI context
160 * @pwd: PRCI WRPLL metadata
161 * @enable: Clock enable or disable value
162 */
163static void __prci_wrpll_write_cfg1(struct __prci_data *pd,
164 struct __prci_wrpll_data *pwd,
165 u32 enable)
166{
167 __prci_writel(enable, pwd->cfg1_offs, pd);
168}
169
156/*
157 * Linux clock framework integration
158 *
159 * See the Linux clock framework documentation for more information on
160 * these functions.
161 */
162
163unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,

--- 30 unchanged lines hidden (view full) ---

194
195 r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
196 if (r)
197 return r;
198
199 if (pwd->enable_bypass)
200 pwd->enable_bypass(pd);
201
170/*
171 * Linux clock framework integration
172 *
173 * See the Linux clock framework documentation for more information on
174 * these functions.
175 */
176
177unsigned long sifive_prci_wrpll_recalc_rate(struct clk_hw *hw,

--- 30 unchanged lines hidden (view full) ---

208
209 r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
210 if (r)
211 return r;
212
213 if (pwd->enable_bypass)
214 pwd->enable_bypass(pd);
215
202 __prci_wrpll_write_cfg(pd, pwd, &pwd->c);
216 __prci_wrpll_write_cfg0(pd, pwd, &pwd->c);
203
204 udelay(wrpll_calc_max_lock_us(&pwd->c));
205
217
218 udelay(wrpll_calc_max_lock_us(&pwd->c));
219
220 return 0;
221}
222
223int sifive_clk_is_enabled(struct clk_hw *hw)
224{
225 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
226 struct __prci_wrpll_data *pwd = pc->pwd;
227 struct __prci_data *pd = pc->pd;
228 u32 r;
229
230 r = __prci_readl(pd, pwd->cfg1_offs);
231
232 if (r & PRCI_COREPLLCFG1_CKE_MASK)
233 return 1;
234 else
235 return 0;
236}
237
238int sifive_prci_clock_enable(struct clk_hw *hw)
239{
240 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
241 struct __prci_wrpll_data *pwd = pc->pwd;
242 struct __prci_data *pd = pc->pd;
243
244 if (sifive_clk_is_enabled(hw))
245 return 0;
246
247 __prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
248
206 if (pwd->disable_bypass)
207 pwd->disable_bypass(pd);
208
209 return 0;
210}
211
249 if (pwd->disable_bypass)
250 pwd->disable_bypass(pd);
251
252 return 0;
253}
254
255void sifive_prci_clock_disable(struct clk_hw *hw)
256{
257 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
258 struct __prci_wrpll_data *pwd = pc->pwd;
259 struct __prci_data *pd = pc->pd;
260 u32 r;
261
262 if (pwd->enable_bypass)
263 pwd->enable_bypass(pd);
264
265 r = __prci_readl(pd, pwd->cfg1_offs);
266 r &= ~PRCI_COREPLLCFG1_CKE_MASK;
267
268 __prci_wrpll_write_cfg1(pd, pwd, r);
269}
270
212/* TLCLKSEL clock integration */
213
214unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
215 unsigned long parent_rate)
216{
217 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
218 struct __prci_data *pd = pc->pd;
219 u32 v;

--- 202 unchanged lines hidden (view full) ---

422 init.parent_names = &pic->parent_name;
423 init.num_parents = 1;
424 init.ops = pic->ops;
425 pic->hw.init = &init;
426
427 pic->pd = pd;
428
429 if (pic->pwd)
271/* TLCLKSEL clock integration */
272
273unsigned long sifive_prci_tlclksel_recalc_rate(struct clk_hw *hw,
274 unsigned long parent_rate)
275{
276 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
277 struct __prci_data *pd = pc->pd;
278 u32 v;

--- 202 unchanged lines hidden (view full) ---

481 init.parent_names = &pic->parent_name;
482 init.num_parents = 1;
483 init.ops = pic->ops;
484 pic->hw.init = &init;
485
486 pic->pd = pd;
487
488 if (pic->pwd)
430 __prci_wrpll_read_cfg(pd, pic->pwd);
489 __prci_wrpll_read_cfg0(pd, pic->pwd);
431
432 r = devm_clk_hw_register(dev, &pic->hw);
433 if (r) {
434 dev_warn(dev, "Failed to register clock %s: %d\n",
435 init.name, r);
436 return r;
437 }
438

--- 77 unchanged lines hidden ---
490
491 r = devm_clk_hw_register(dev, &pic->hw);
492 if (r) {
493 dev_warn(dev, "Failed to register clock %s: %d\n",
494 init.name, r);
495 return r;
496 }
497

--- 77 unchanged lines hidden ---