sifive-prci.c (c816e1ddf2b60b31d121118488c5a854d9a2fad9) sifive-prci.c (efc91ae43c8d4bbf64e4b9a28113b24a74ffd58d)
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>
9#include <linux/io.h>
10#include <linux/of_device.h>
11#include "sifive-prci.h"
12#include "fu540-prci.h"
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>
9#include <linux/io.h>
10#include <linux/of_device.h>
11#include "sifive-prci.h"
12#include "fu540-prci.h"
13#include "fu740-prci.h"
13
14/*
15 * Private functions
16 */
17
18/**
19 * __prci_readl() - read from a PRCI register
20 * @pd: PRCI context

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

220
221 v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
222 v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
223 div = v ? 1 : 2;
224
225 return div_u64(parent_rate, div);
226}
227
14
15/*
16 * Private functions
17 */
18
19/**
20 * __prci_readl() - read from a PRCI register
21 * @pd: PRCI context

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

221
222 v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
223 v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
224 div = v ? 1 : 2;
225
226 return div_u64(parent_rate, div);
227}
228
229/* HFPCLK clock integration */
230
231unsigned long sifive_prci_hfpclkplldiv_recalc_rate(struct clk_hw *hw,
232 unsigned long parent_rate)
233{
234 struct __prci_clock *pc = clk_hw_to_prci_clock(hw);
235 struct __prci_data *pd = pc->pd;
236 u32 div = __prci_readl(pd, PRCI_HFPCLKPLLDIV_OFFSET);
237
238 return div_u64(parent_rate, div + 2);
239}
240
228/*
229 * Core clock mux control
230 */
231
232/**
233 * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
234 * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
235 *

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

266 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
267 r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
268 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
269
270 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
271}
272
273/**
241/*
242 * Core clock mux control
243 */
244
245/**
246 * sifive_prci_coreclksel_use_hfclk() - switch the CORECLK mux to output HFCLK
247 * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
248 *

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

279 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
280 r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
281 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
282
283 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
284}
285
286/**
287 * sifive_prci_coreclksel_use_final_corepll() - switch the CORECLK mux to output
288 * FINAL_COREPLL
289 * @pd: struct __prci_data * for the PRCI containing the CORECLK mux reg
290 *
291 * Switch the CORECLK mux to the final COREPLL output clock; return once
292 * complete.
293 *
294 * Context: Any context. Caller must prevent concurrent changes to the
295 * PRCI_CORECLKSEL_OFFSET register.
296 */
297void sifive_prci_coreclksel_use_final_corepll(struct __prci_data *pd)
298{
299 u32 r;
300
301 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET);
302 r &= ~PRCI_CORECLKSEL_CORECLKSEL_MASK;
303 __prci_writel(r, PRCI_CORECLKSEL_OFFSET, pd);
304
305 r = __prci_readl(pd, PRCI_CORECLKSEL_OFFSET); /* barrier */
306}
307
308/**
309 * sifive_prci_corepllsel_use_dvfscorepll() - switch the COREPLL mux to
310 * output DVFS_COREPLL
311 * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
312 *
313 * Switch the COREPLL mux to the DVFSCOREPLL output clock; return once complete.
314 *
315 * Context: Any context. Caller must prevent concurrent changes to the
316 * PRCI_COREPLLSEL_OFFSET register.
317 */
318void sifive_prci_corepllsel_use_dvfscorepll(struct __prci_data *pd)
319{
320 u32 r;
321
322 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
323 r |= PRCI_COREPLLSEL_COREPLLSEL_MASK;
324 __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
325
326 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */
327}
328
329/**
330 * sifive_prci_corepllsel_use_corepll() - switch the COREPLL mux to
331 * output COREPLL
332 * @pd: struct __prci_data * for the PRCI containing the COREPLL mux reg
333 *
334 * Switch the COREPLL mux to the COREPLL output clock; return once complete.
335 *
336 * Context: Any context. Caller must prevent concurrent changes to the
337 * PRCI_COREPLLSEL_OFFSET register.
338 */
339void sifive_prci_corepllsel_use_corepll(struct __prci_data *pd)
340{
341 u32 r;
342
343 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET);
344 r &= ~PRCI_COREPLLSEL_COREPLLSEL_MASK;
345 __prci_writel(r, PRCI_COREPLLSEL_OFFSET, pd);
346
347 r = __prci_readl(pd, PRCI_COREPLLSEL_OFFSET); /* barrier */
348}
349
350/**
351 * sifive_prci_hfpclkpllsel_use_hfclk() - switch the HFPCLKPLL mux to
352 * output HFCLK
353 * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
354 *
355 * Switch the HFPCLKPLL mux to the HFCLK input source; return once complete.
356 *
357 * Context: Any context. Caller must prevent concurrent changes to the
358 * PRCI_HFPCLKPLLSEL_OFFSET register.
359 */
360void sifive_prci_hfpclkpllsel_use_hfclk(struct __prci_data *pd)
361{
362 u32 r;
363
364 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
365 r |= PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
366 __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
367
368 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
369}
370
371/**
372 * sifive_prci_hfpclkpllsel_use_hfpclkpll() - switch the HFPCLKPLL mux to
373 * output HFPCLKPLL
374 * @pd: struct __prci_data * for the PRCI containing the HFPCLKPLL mux reg
375 *
376 * Switch the HFPCLKPLL mux to the HFPCLKPLL output clock; return once complete.
377 *
378 * Context: Any context. Caller must prevent concurrent changes to the
379 * PRCI_HFPCLKPLLSEL_OFFSET register.
380 */
381void sifive_prci_hfpclkpllsel_use_hfpclkpll(struct __prci_data *pd)
382{
383 u32 r;
384
385 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET);
386 r &= ~PRCI_HFPCLKPLLSEL_HFPCLKPLLSEL_MASK;
387 __prci_writel(r, PRCI_HFPCLKPLLSEL_OFFSET, pd);
388
389 r = __prci_readl(pd, PRCI_HFPCLKPLLSEL_OFFSET); /* barrier */
390}
391
392/**
274 * __prci_register_clocks() - register clock controls in the PRCI
275 * @dev: Linux struct device
276 * @pd: The pointer for PRCI per-device instance data
277 * @desc: The pointer for the information of clocks of each SoCs
278 *
279 * Register the list of clock controls described in __prci_init_clocks[] with
280 * the Linux clock framework.
281 *

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

372
373 dev_dbg(dev, "SiFive PRCI probed\n");
374
375 return 0;
376}
377
378static const struct of_device_id sifive_prci_of_match[] = {
379 {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540},
393 * __prci_register_clocks() - register clock controls in the PRCI
394 * @dev: Linux struct device
395 * @pd: The pointer for PRCI per-device instance data
396 * @desc: The pointer for the information of clocks of each SoCs
397 *
398 * Register the list of clock controls described in __prci_init_clocks[] with
399 * the Linux clock framework.
400 *

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

491
492 dev_dbg(dev, "SiFive PRCI probed\n");
493
494 return 0;
495}
496
497static const struct of_device_id sifive_prci_of_match[] = {
498 {.compatible = "sifive,fu540-c000-prci", .data = &prci_clk_fu540},
499 {.compatible = "sifive,fu740-c000-prci", .data = &prci_clk_fu740},
380 {}
381};
382
383static struct platform_driver sifive_prci_driver = {
384 .driver = {
385 .name = "sifive-clk-prci",
386 .of_match_table = sifive_prci_of_match,
387 },
388 .probe = sifive_prci_probe,
389};
390
391static int __init sifive_prci_init(void)
392{
393 return platform_driver_register(&sifive_prci_driver);
394}
395core_initcall(sifive_prci_init);
500 {}
501};
502
503static struct platform_driver sifive_prci_driver = {
504 .driver = {
505 .name = "sifive-clk-prci",
506 .of_match_table = sifive_prci_of_match,
507 },
508 .probe = sifive_prci_probe,
509};
510
511static int __init sifive_prci_init(void)
512{
513 return platform_driver_register(&sifive_prci_driver);
514}
515core_initcall(sifive_prci_init);