1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2017, Intel Corporation
5 #include <linux/slab.h>
6 #include <linux/clk-provider.h>
9 #include "stratix10-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
);
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
);
85 div
= ((readl(socfpgaclk
->hw
.reg
) &
86 SWCTRLBTCLKSEL_MASK
) >>
87 SWCTRLBTCLKSEL_SHIFT
);
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
);
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
);
108 pll_src
= readl(socfpgaclk
->hw
.reg
);
109 return (pll_src
>> SWCTRLBTCLKSEL_SHIFT
) &
113 static int clk_pll_prepare(struct clk_hw
*hwclk
)
115 struct socfpga_pll
*socfpgaclk
= to_socfpga_clk(hwclk
);
118 /* Bring PLL out of reset */
119 reg
= readl(socfpgaclk
->hw
.reg
);
120 reg
|= SOCFPGA_PLL_RESET_MASK
;
121 writel(reg
, socfpgaclk
->hw
.reg
);
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
,
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
))
156 pll_clk
->hw
.reg
= reg
+ clks
->offset
;
158 if (streq(name
, SOCFPGA_BOOT_CLK
))
159 init
.ops
= &clk_boot_ops
;
161 init
.ops
= &clk_pll_ops
;
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
))) {
181 struct clk
*agilex_register_pll(const struct stratix10_pll_clock
*clks
,
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
))
193 pll_clk
->hw
.reg
= reg
+ clks
->offset
;
195 if (streq(name
, SOCFPGA_BOOT_CLK
))
196 init
.ops
= &clk_boot_ops
;
198 init
.ops
= &agilex_clk_pll_ops
;
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
))) {