• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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
29 
30 #define SOCFPGA_BOOT_CLK		"boot_clk"
31 
32 #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
33 
agilex_clk_pll_recalc_rate(struct clk_hw * hwclk,unsigned long parent_rate)34 static unsigned long agilex_clk_pll_recalc_rate(struct clk_hw *hwclk,
35 						unsigned long parent_rate)
36 {
37 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
38 	unsigned long arefdiv, reg, mdiv;
39 	unsigned long long vco_freq;
40 
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;
44 
45 	vco_freq = (unsigned long long)parent_rate / arefdiv;
46 
47 	/* Read mdiv and fdiv from the fdbck register */
48 	reg = readl(socfpgaclk->hw.reg + 0x24);
49 	mdiv = reg & SOCFPGA_AGILEX_PLL_MDIV_MASK;
50 
51 	vco_freq = (unsigned long long)vco_freq * mdiv;
52 	return (unsigned long)vco_freq;
53 }
54 
clk_pll_recalc_rate(struct clk_hw * hwclk,unsigned long parent_rate)55 static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
56 					 unsigned long parent_rate)
57 {
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;
63 
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;
67 
68 	vco_freq = parent_rate;
69 	do_div(vco_freq, refdiv);
70 
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);
75 
76 	return (unsigned long)vco_freq;
77 }
78 
clk_boot_clk_recalc_rate(struct clk_hw * hwclk,unsigned long parent_rate)79 static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk,
80 					 unsigned long parent_rate)
81 {
82 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
83 	u32 div = 1;
84 
85 	div = ((readl(socfpgaclk->hw.reg) &
86 		SWCTRLBTCLKSEL_MASK) >>
87 		SWCTRLBTCLKSEL_SHIFT);
88 	div += 1;
89 	return parent_rate /= div;
90 }
91 
92 
clk_pll_get_parent(struct clk_hw * hwclk)93 static u8 clk_pll_get_parent(struct clk_hw *hwclk)
94 {
95 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
96 	u32 pll_src;
97 
98 	pll_src = readl(socfpgaclk->hw.reg);
99 	return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
100 		CLK_MGR_PLL_CLK_SRC_MASK;
101 }
102 
clk_boot_get_parent(struct clk_hw * hwclk)103 static u8 clk_boot_get_parent(struct clk_hw *hwclk)
104 {
105 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
106 	u32 pll_src;
107 
108 	pll_src = readl(socfpgaclk->hw.reg);
109 	return (pll_src >> SWCTRLBTCLKSEL_SHIFT) &
110 		SWCTRLBTCLKSEL_MASK;
111 }
112 
clk_pll_prepare(struct clk_hw * hwclk)113 static int clk_pll_prepare(struct clk_hw *hwclk)
114 {
115 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
116 	u32 reg;
117 
118 	/* Bring PLL out of reset */
119 	reg = readl(socfpgaclk->hw.reg);
120 	reg |= SOCFPGA_PLL_RESET_MASK;
121 	writel(reg, socfpgaclk->hw.reg);
122 
123 	return 0;
124 }
125 
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,
130 };
131 
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,
136 };
137 
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,
142 };
143 
s10_register_pll(const struct stratix10_pll_clock * clks,void __iomem * reg)144 struct clk *s10_register_pll(const struct stratix10_pll_clock *clks,
145 			     void __iomem *reg)
146 {
147 	struct clk *clk;
148 	struct socfpga_pll *pll_clk;
149 	struct clk_init_data init;
150 	const char *name = clks->name;
151 
152 	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
153 	if (WARN_ON(!pll_clk))
154 		return NULL;
155 
156 	pll_clk->hw.reg = reg + clks->offset;
157 
158 	if (streq(name, SOCFPGA_BOOT_CLK))
159 		init.ops = &clk_boot_ops;
160 	else
161 		init.ops = &clk_pll_ops;
162 
163 	init.name = name;
164 	init.flags = clks->flags;
165 
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;
170 
171 	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
172 
173 	clk = clk_register(NULL, &pll_clk->hw.hw);
174 	if (WARN_ON(IS_ERR(clk))) {
175 		kfree(pll_clk);
176 		return NULL;
177 	}
178 	return clk;
179 }
180 
agilex_register_pll(const struct stratix10_pll_clock * clks,void __iomem * reg)181 struct clk *agilex_register_pll(const struct stratix10_pll_clock *clks,
182 				void __iomem *reg)
183 {
184 	struct clk *clk;
185 	struct socfpga_pll *pll_clk;
186 	struct clk_init_data init;
187 	const char *name = clks->name;
188 
189 	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
190 	if (WARN_ON(!pll_clk))
191 		return NULL;
192 
193 	pll_clk->hw.reg = reg + clks->offset;
194 
195 	if (streq(name, SOCFPGA_BOOT_CLK))
196 		init.ops = &clk_boot_ops;
197 	else
198 		init.ops = &agilex_clk_pll_ops;
199 
200 	init.name = name;
201 	init.flags = clks->flags;
202 
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;
207 
208 	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
209 
210 	clk = clk_register(NULL, &pll_clk->hw.hw);
211 	if (WARN_ON(IS_ERR(clk))) {
212 		kfree(pll_clk);
213 		return NULL;
214 	}
215 	return clk;
216 }
217