Lines Matching +full:pll +full:- +full:source

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
6 #define pr_fmt(fmt) "k210-clk: " fmt
15 #include <linux/clk-provider.h>
18 #include <soc/canaan/k210-sysctl.h>
20 #include <dt-bindings/clock/k210-clk.h>
253 * PLL control register bits.
268 * PLL lock register bits.
322 * struct k210_sysclk - sysclk driver data
354 struct k210_pll *pll) in k210_init_pll() argument
356 pll->id = pllid; in k210_init_pll()
357 pll->reg = regs + k210_plls_cfg[pllid].reg; in k210_init_pll()
358 pll->lock = regs + K210_SYSCTL_PLL_LOCK; in k210_init_pll()
359 pll->lock_shift = k210_plls_cfg[pllid].lock_shift; in k210_init_pll()
360 pll->lock_width = k210_plls_cfg[pllid].lock_width; in k210_init_pll()
363 static void k210_pll_wait_for_lock(struct k210_pll *pll) in k210_pll_wait_for_lock() argument
365 u32 reg, mask = GENMASK(pll->lock_shift + pll->lock_width - 1, in k210_pll_wait_for_lock()
366 pll->lock_shift); in k210_pll_wait_for_lock()
369 reg = readl(pll->lock); in k210_pll_wait_for_lock()
373 reg |= BIT(pll->lock_shift + K210_PLL_CLEAR_SLIP); in k210_pll_wait_for_lock()
374 writel(reg, pll->lock); in k210_pll_wait_for_lock()
378 static bool k210_pll_hw_is_enabled(struct k210_pll *pll) in k210_pll_hw_is_enabled() argument
380 u32 reg = readl(pll->reg); in k210_pll_hw_is_enabled()
389 static void k210_pll_enable_hw(void __iomem *regs, struct k210_pll *pll) in k210_pll_enable_hw() argument
391 struct k210_pll_cfg *pll_cfg = &k210_plls_cfg[pll->id]; in k210_pll_enable_hw()
394 if (k210_pll_hw_is_enabled(pll)) in k210_pll_enable_hw()
398 * For PLL0, we need to re-parent ACLK to IN0 to keep the CPU cores and in k210_pll_enable_hw()
401 if (pll->id == K210_PLL0) in k210_pll_enable_hw()
404 /* Set PLL factors */ in k210_pll_enable_hw()
405 reg = readl(pll->reg); in k210_pll_enable_hw()
407 reg |= FIELD_PREP(K210_PLL_CLKR, pll_cfg->r); in k210_pll_enable_hw()
408 reg |= FIELD_PREP(K210_PLL_CLKF, pll_cfg->f); in k210_pll_enable_hw()
409 reg |= FIELD_PREP(K210_PLL_CLKOD, pll_cfg->od); in k210_pll_enable_hw()
410 reg |= FIELD_PREP(K210_PLL_BWADJ, pll_cfg->bwadj); in k210_pll_enable_hw()
412 writel(reg, pll->reg); in k210_pll_enable_hw()
415 * Reset the PLL: ensure reset is low before asserting it. in k210_pll_enable_hw()
419 writel(reg, pll->reg); in k210_pll_enable_hw()
421 writel(reg, pll->reg); in k210_pll_enable_hw()
425 writel(reg, pll->reg); in k210_pll_enable_hw()
427 k210_pll_wait_for_lock(pll); in k210_pll_enable_hw()
431 writel(reg, pll->reg); in k210_pll_enable_hw()
433 if (pll->id == K210_PLL0) in k210_pll_enable_hw()
439 struct k210_pll *pll = to_k210_pll(hw); in k210_pll_enable() local
440 struct k210_sysclk *ksc = pll->ksc; in k210_pll_enable()
443 spin_lock_irqsave(&ksc->clk_lock, flags); in k210_pll_enable()
445 k210_pll_enable_hw(ksc->regs, pll); in k210_pll_enable()
447 spin_unlock_irqrestore(&ksc->clk_lock, flags); in k210_pll_enable()
454 struct k210_pll *pll = to_k210_pll(hw); in k210_pll_disable() local
455 struct k210_sysclk *ksc = pll->ksc; in k210_pll_disable()
464 spin_lock_irqsave(&ksc->clk_lock, flags); in k210_pll_disable()
465 reg = readl(pll->reg); in k210_pll_disable()
467 writel(reg, pll->reg); in k210_pll_disable()
471 writel(reg, pll->reg); in k210_pll_disable()
472 spin_unlock_irqrestore(&ksc->clk_lock, flags); in k210_pll_disable()
483 struct k210_pll *pll = to_k210_pll(hw); in k210_pll_get_rate() local
484 u32 reg = readl(pll->reg); in k210_pll_get_rate()
509 struct k210_pll *pll = to_k210_pll(hw); in k210_pll2_set_parent() local
510 struct k210_sysclk *ksc = pll->ksc; in k210_pll2_set_parent()
514 spin_lock_irqsave(&ksc->clk_lock, flags); in k210_pll2_set_parent()
516 reg = readl(pll->reg); in k210_pll2_set_parent()
519 writel(reg, pll->reg); in k210_pll2_set_parent()
521 spin_unlock_irqrestore(&ksc->clk_lock, flags); in k210_pll2_set_parent()
528 struct k210_pll *pll = to_k210_pll(hw); in k210_pll2_get_parent() local
529 u32 reg = readl(pll->reg); in k210_pll2_get_parent()
549 struct k210_pll *pll = &ksc->plls[pllid]; in k210_register_pll() local
553 { .hw = &ksc->plls[K210_PLL0].hw }, in k210_register_pll()
554 { .hw = &ksc->plls[K210_PLL1].hw }, in k210_register_pll()
562 pll->hw.init = &init; in k210_register_pll()
563 pll->ksc = ksc; in k210_register_pll()
565 return of_clk_hw_register(np, &pll->hw); in k210_register_pll()
574 k210_init_pll(ksc->regs, i, &ksc->plls[i]); in k210_register_plls()
603 spin_lock_irqsave(&ksc->clk_lock, flags); in k210_aclk_set_parent()
605 k210_aclk_set_selector(ksc->regs, index); in k210_aclk_set_parent()
607 spin_unlock_irqrestore(&ksc->clk_lock, flags); in k210_aclk_set_parent()
617 sel = readl(ksc->regs + K210_SYSCTL_SEL0) & K210_ACLK_SEL; in k210_aclk_get_parent()
626 u32 reg = readl(ksc->regs + K210_SYSCTL_SEL0); in k210_aclk_get_rate()
653 { .hw = &ksc->plls[K210_PLL0].hw }, in k210_register_aclk()
661 ksc->aclk.init = &init; in k210_register_aclk()
663 ret = of_clk_hw_register(np, &ksc->aclk); in k210_register_aclk()
677 struct k210_sysclk *ksc = kclk->ksc; in k210_clk_enable()
678 struct k210_clk_cfg *cfg = &k210_clk_cfgs[kclk->id]; in k210_clk_enable()
682 if (!cfg->gate_reg) in k210_clk_enable()
685 spin_lock_irqsave(&ksc->clk_lock, flags); in k210_clk_enable()
686 reg = readl(ksc->regs + cfg->gate_reg); in k210_clk_enable()
687 reg |= BIT(cfg->gate_bit); in k210_clk_enable()
688 writel(reg, ksc->regs + cfg->gate_reg); in k210_clk_enable()
689 spin_unlock_irqrestore(&ksc->clk_lock, flags); in k210_clk_enable()
697 struct k210_sysclk *ksc = kclk->ksc; in k210_clk_disable()
698 struct k210_clk_cfg *cfg = &k210_clk_cfgs[kclk->id]; in k210_clk_disable()
702 if (!cfg->gate_reg) in k210_clk_disable()
705 spin_lock_irqsave(&ksc->clk_lock, flags); in k210_clk_disable()
706 reg = readl(ksc->regs + cfg->gate_reg); in k210_clk_disable()
707 reg &= ~BIT(cfg->gate_bit); in k210_clk_disable()
708 writel(reg, ksc->regs + cfg->gate_reg); in k210_clk_disable()
709 spin_unlock_irqrestore(&ksc->clk_lock, flags); in k210_clk_disable()
715 struct k210_sysclk *ksc = kclk->ksc; in k210_clk_set_parent()
716 struct k210_clk_cfg *cfg = &k210_clk_cfgs[kclk->id]; in k210_clk_set_parent()
720 spin_lock_irqsave(&ksc->clk_lock, flags); in k210_clk_set_parent()
721 reg = readl(ksc->regs + cfg->mux_reg); in k210_clk_set_parent()
723 reg |= BIT(cfg->mux_bit); in k210_clk_set_parent()
725 reg &= ~BIT(cfg->mux_bit); in k210_clk_set_parent()
726 writel(reg, ksc->regs + cfg->mux_reg); in k210_clk_set_parent()
727 spin_unlock_irqrestore(&ksc->clk_lock, flags); in k210_clk_set_parent()
735 struct k210_sysclk *ksc = kclk->ksc; in k210_clk_get_parent()
736 struct k210_clk_cfg *cfg = &k210_clk_cfgs[kclk->id]; in k210_clk_get_parent()
740 spin_lock_irqsave(&ksc->clk_lock, flags); in k210_clk_get_parent()
741 reg = readl(ksc->regs + cfg->mux_reg); in k210_clk_get_parent()
742 idx = (reg & BIT(cfg->mux_bit)) ? 1 : 0; in k210_clk_get_parent()
743 spin_unlock_irqrestore(&ksc->clk_lock, flags); in k210_clk_get_parent()
752 struct k210_sysclk *ksc = kclk->ksc; in k210_clk_get_rate()
753 struct k210_clk_cfg *cfg = &k210_clk_cfgs[kclk->id]; in k210_clk_get_rate()
756 if (!cfg->div_reg) in k210_clk_get_rate()
759 reg = readl(ksc->regs + cfg->div_reg); in k210_clk_get_rate()
760 div_val = (reg >> cfg->div_shift) & GENMASK(cfg->div_width - 1, 0); in k210_clk_get_rate()
762 switch (cfg->div_type) { in k210_clk_get_rate()
795 struct k210_clk *kclk = &ksc->clks[id]; in k210_register_clk()
808 kclk->id = id; in k210_register_clk()
809 kclk->ksc = ksc; in k210_register_clk()
810 kclk->hw.init = &init; in k210_register_clk()
812 ret = of_clk_hw_register(np, &kclk->hw); in k210_register_clk()
816 kclk->id = -1; in k210_register_clk()
828 { .hw = &ksc->plls[K210_PLL0].hw } in k210_register_mux_clk()
850 .hw = &ksc->plls[pllid].hw, in k210_register_pll_child()
861 .hw = &ksc->aclk, in k210_register_aclk_child()
872 .hw = &ksc->clks[parent_id].hw, in k210_register_clk_child()
882 unsigned int idx = clkspec->args[0]; in k210_clk_hw_onecell_get()
885 return ERR_PTR(-EINVAL); in k210_clk_hw_onecell_get()
887 return &ksc->clks[idx].hw; in k210_clk_hw_onecell_get()
900 spin_lock_init(&ksc->clk_lock); in k210_clk_init()
902 ksc->regs = of_iomap(sysctl_np, 0); in k210_clk_init()
904 if (!ksc->regs) { in k210_clk_init()
931 /* Clocks with aclk as source */ in k210_clk_init()
940 /* Clocks with PLL0 as source */ in k210_clk_init()
948 /* Clocks with PLL2 as source */ in k210_clk_init()
956 /* Clocks with IN0 as source */ in k210_clk_init()
961 /* Clocks with APB0 as source */ in k210_clk_init()
969 /* Clocks with APB1 as source */ in k210_clk_init()
973 /* Mux clocks with in0 or pll0 as source */ in k210_clk_init()
981 if (ksc->clks[i].id != i) in k210_clk_init()
992 np, clk_hw_get_rate(&ksc->clks[K210_CLK_CPU].hw) / 1000000); in k210_clk_init()
995 CLK_OF_DECLARE(k210_clk, "canaan,k210-clk", k210_clk_init);