WIP FPC-III support
[linux/fpc-iii.git] / drivers / clk / socfpga / clk-pll-s10.c
blob4e268953b7da2c9dc7828364242cbb7f584da479
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>
9 #include "stratix10-clk.h"
10 #include "clk.h"
12 /* Clock Manager offsets */
13 #define CLK_MGR_PLL_CLK_SRC_SHIFT 16
14 #define CLK_MGR_PLL_CLK_SRC_MASK 0x3
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_AREFDIV_MASK 0x00000F00
22 #define SOCFPGA_PLL_DREFDIV_MASK 0x00003000
23 #define SOCFPGA_PLL_DREFDIV_SHIFT 12
24 #define SOCFPGA_PLL_MDIV_MASK 0xFF000000
25 #define SOCFPGA_PLL_MDIV_SHIFT 24
26 #define SOCFPGA_AGILEX_PLL_MDIV_MASK 0x000003FF
27 #define SWCTRLBTCLKSEL_MASK 0x200
28 #define SWCTRLBTCLKSEL_SHIFT 9
30 #define SOCFPGA_BOOT_CLK "boot_clk"
32 #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
34 static unsigned long agilex_clk_pll_recalc_rate(struct clk_hw *hwclk,
35 unsigned long parent_rate)
37 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
38 unsigned long arefdiv, reg, mdiv;
39 unsigned long long vco_freq;
41 /* read VCO1 reg for numerator and denominator */
42 reg = readl(socfpgaclk->hw.reg);
43 arefdiv = (reg & SOCFPGA_PLL_AREFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
45 vco_freq = (unsigned long long)parent_rate / arefdiv;
47 /* Read mdiv and fdiv from the fdbck register */
48 reg = readl(socfpgaclk->hw.reg + 0x24);
49 mdiv = reg & SOCFPGA_AGILEX_PLL_MDIV_MASK;
51 vco_freq = (unsigned long long)vco_freq * mdiv;
52 return (unsigned long)vco_freq;
55 static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
56 unsigned long parent_rate)
58 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
59 unsigned long mdiv;
60 unsigned long refdiv;
61 unsigned long reg;
62 unsigned long long vco_freq;
64 /* read VCO1 reg for numerator and denominator */
65 reg = readl(socfpgaclk->hw.reg);
66 refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
68 vco_freq = parent_rate;
69 do_div(vco_freq, refdiv);
71 /* Read mdiv and fdiv from the fdbck register */
72 reg = readl(socfpgaclk->hw.reg + 0x4);
73 mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT;
74 vco_freq = (unsigned long long)vco_freq * (mdiv + 6);
76 return (unsigned long)vco_freq;
79 static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk,
80 unsigned long parent_rate)
82 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
83 u32 div = 1;
85 div = ((readl(socfpgaclk->hw.reg) &
86 SWCTRLBTCLKSEL_MASK) >>
87 SWCTRLBTCLKSEL_SHIFT);
88 div += 1;
89 return parent_rate /= div;
93 static u8 clk_pll_get_parent(struct clk_hw *hwclk)
95 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
96 u32 pll_src;
98 pll_src = readl(socfpgaclk->hw.reg);
99 return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
100 CLK_MGR_PLL_CLK_SRC_MASK;
103 static u8 clk_boot_get_parent(struct clk_hw *hwclk)
105 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
106 u32 pll_src;
108 pll_src = readl(socfpgaclk->hw.reg);
109 return (pll_src >> SWCTRLBTCLKSEL_SHIFT) &
110 SWCTRLBTCLKSEL_MASK;
113 static int clk_pll_prepare(struct clk_hw *hwclk)
115 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
116 u32 reg;
118 /* Bring PLL out of reset */
119 reg = readl(socfpgaclk->hw.reg);
120 reg |= SOCFPGA_PLL_RESET_MASK;
121 writel(reg, socfpgaclk->hw.reg);
123 return 0;
126 static const struct clk_ops agilex_clk_pll_ops = {
127 .recalc_rate = agilex_clk_pll_recalc_rate,
128 .get_parent = clk_pll_get_parent,
129 .prepare = clk_pll_prepare,
132 static const struct clk_ops clk_pll_ops = {
133 .recalc_rate = clk_pll_recalc_rate,
134 .get_parent = clk_pll_get_parent,
135 .prepare = clk_pll_prepare,
138 static const struct clk_ops clk_boot_ops = {
139 .recalc_rate = clk_boot_clk_recalc_rate,
140 .get_parent = clk_boot_get_parent,
141 .prepare = clk_pll_prepare,
144 struct clk *s10_register_pll(const struct stratix10_pll_clock *clks,
145 void __iomem *reg)
147 struct clk *clk;
148 struct socfpga_pll *pll_clk;
149 struct clk_init_data init;
150 const char *name = clks->name;
152 pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
153 if (WARN_ON(!pll_clk))
154 return NULL;
156 pll_clk->hw.reg = reg + clks->offset;
158 if (streq(name, SOCFPGA_BOOT_CLK))
159 init.ops = &clk_boot_ops;
160 else
161 init.ops = &clk_pll_ops;
163 init.name = name;
164 init.flags = clks->flags;
166 init.num_parents = clks->num_parents;
167 init.parent_names = NULL;
168 init.parent_data = clks->parent_data;
169 pll_clk->hw.hw.init = &init;
171 pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
173 clk = clk_register(NULL, &pll_clk->hw.hw);
174 if (WARN_ON(IS_ERR(clk))) {
175 kfree(pll_clk);
176 return NULL;
178 return clk;
181 struct clk *agilex_register_pll(const struct stratix10_pll_clock *clks,
182 void __iomem *reg)
184 struct clk *clk;
185 struct socfpga_pll *pll_clk;
186 struct clk_init_data init;
187 const char *name = clks->name;
189 pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
190 if (WARN_ON(!pll_clk))
191 return NULL;
193 pll_clk->hw.reg = reg + clks->offset;
195 if (streq(name, SOCFPGA_BOOT_CLK))
196 init.ops = &clk_boot_ops;
197 else
198 init.ops = &agilex_clk_pll_ops;
200 init.name = name;
201 init.flags = clks->flags;
203 init.num_parents = clks->num_parents;
204 init.parent_names = NULL;
205 init.parent_data = clks->parent_data;
206 pll_clk->hw.hw.init = &init;
208 pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
210 clk = clk_register(NULL, &pll_clk->hw.hw);
211 if (WARN_ON(IS_ERR(clk))) {
212 kfree(pll_clk);
213 return NULL;
215 return clk;