1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2017, Intel Corporation 4 */ 5 #include <linux/slab.h> 6 #include <linux/clk-provider.h> 7 #include <linux/io.h> 8 9 #include "stratix10-clk.h" 10 #include "clk.h" 11 12 /* Clock Manager offsets */ 13 #define CLK_MGR_PLL_CLK_SRC_SHIFT 16 14 #define CLK_MGR_PLL_CLK_SRC_MASK 0x3 15 16 /* PLL Clock enable bits */ 17 #define SOCFPGA_PLL_POWER 0 18 #define SOCFPGA_PLL_RESET_MASK 0x2 19 #define SOCFPGA_PLL_REFDIV_MASK 0x00003F00 20 #define SOCFPGA_PLL_REFDIV_SHIFT 8 21 #define SOCFPGA_PLL_MDIV_MASK 0xFF000000 22 #define SOCFPGA_PLL_MDIV_SHIFT 24 23 #define SWCTRLBTCLKSEL_MASK 0x200 24 #define SWCTRLBTCLKSEL_SHIFT 9 25 26 #define SOCFPGA_BOOT_CLK "boot_clk" 27 28 #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw) 29 30 static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, 31 unsigned long parent_rate) 32 { 33 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 34 unsigned long mdiv; 35 unsigned long refdiv; 36 unsigned long reg; 37 unsigned long long vco_freq; 38 39 /* read VCO1 reg for numerator and denominator */ 40 reg = readl(socfpgaclk->hw.reg); 41 refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT; 42 43 vco_freq = parent_rate; 44 do_div(vco_freq, refdiv); 45 46 /* Read mdiv and fdiv from the fdbck register */ 47 reg = readl(socfpgaclk->hw.reg + 0x4); 48 mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT; 49 vco_freq = (unsigned long long)vco_freq * (mdiv + 6); 50 51 return (unsigned long)vco_freq; 52 } 53 54 static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk, 55 unsigned long parent_rate) 56 { 57 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 58 u32 div = 1; 59 60 div = ((readl(socfpgaclk->hw.reg) & 61 SWCTRLBTCLKSEL_MASK) >> 62 SWCTRLBTCLKSEL_SHIFT); 63 div += 1; 64 return parent_rate /= div; 65 } 66 67 68 static u8 clk_pll_get_parent(struct clk_hw *hwclk) 69 { 70 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 71 u32 pll_src; 72 73 pll_src = readl(socfpgaclk->hw.reg); 74 return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) & 75 CLK_MGR_PLL_CLK_SRC_MASK; 76 } 77 78 static u8 clk_boot_get_parent(struct clk_hw *hwclk) 79 { 80 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 81 u32 pll_src; 82 83 pll_src = readl(socfpgaclk->hw.reg); 84 return (pll_src >> SWCTRLBTCLKSEL_SHIFT) & 85 SWCTRLBTCLKSEL_MASK; 86 } 87 88 static int clk_pll_prepare(struct clk_hw *hwclk) 89 { 90 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 91 u32 reg; 92 93 /* Bring PLL out of reset */ 94 reg = readl(socfpgaclk->hw.reg); 95 reg |= SOCFPGA_PLL_RESET_MASK; 96 writel(reg, socfpgaclk->hw.reg); 97 98 return 0; 99 } 100 101 static struct clk_ops clk_pll_ops = { 102 .recalc_rate = clk_pll_recalc_rate, 103 .get_parent = clk_pll_get_parent, 104 .prepare = clk_pll_prepare, 105 }; 106 107 static struct clk_ops clk_boot_ops = { 108 .recalc_rate = clk_boot_clk_recalc_rate, 109 .get_parent = clk_boot_get_parent, 110 .prepare = clk_pll_prepare, 111 }; 112 113 struct clk *s10_register_pll(const struct stratix10_pll_clock *clks, 114 void __iomem *reg) 115 { 116 struct clk *clk; 117 struct socfpga_pll *pll_clk; 118 struct clk_init_data init; 119 const char *name = clks->name; 120 const char * const *parent_names = clks->parent_names; 121 122 pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); 123 if (WARN_ON(!pll_clk)) 124 return NULL; 125 126 pll_clk->hw.reg = reg + clks->offset; 127 128 if (streq(name, SOCFPGA_BOOT_CLK)) 129 init.ops = &clk_boot_ops; 130 else 131 init.ops = &clk_pll_ops; 132 133 init.name = name; 134 init.flags = clks->flags; 135 136 init.num_parents = clks->num_parents; 137 init.parent_names = parent_names; 138 pll_clk->hw.hw.init = &init; 139 140 pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER; 141 clk_pll_ops.enable = clk_gate_ops.enable; 142 clk_pll_ops.disable = clk_gate_ops.disable; 143 144 clk = clk_register(NULL, &pll_clk->hw.hw); 145 if (WARN_ON(IS_ERR(clk))) { 146 kfree(pll_clk); 147 return NULL; 148 } 149 return clk; 150 } 151