xref: /linux/drivers/clk/microchip/clk-mpfs.c (revision cdd30ebb1b9f36159d66f088b61aee264e649d7a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * PolarFire SoC MSS/core complex clock control
4  *
5  * Copyright (C) 2020-2022 Microchip Technology Inc. All rights reserved.
6  */
7 #include <linux/clk-provider.h>
8 #include <linux/io.h>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <dt-bindings/clock/microchip,mpfs-clock.h>
12 #include <soc/microchip/mpfs.h>
13 
14 /* address offset of control registers */
15 #define REG_MSSPLL_REF_CR	0x08u
16 #define REG_MSSPLL_POSTDIV01_CR	0x10u
17 #define REG_MSSPLL_POSTDIV23_CR	0x14u
18 #define REG_MSSPLL_SSCG_2_CR	0x2Cu
19 #define REG_CLOCK_CONFIG_CR	0x08u
20 #define REG_RTC_CLOCK_CR	0x0Cu
21 #define REG_SUBBLK_CLOCK_CR	0x84u
22 #define REG_SUBBLK_RESET_CR	0x88u
23 
24 #define MSSPLL_FBDIV_SHIFT	0x00u
25 #define MSSPLL_FBDIV_WIDTH	0x0Cu
26 #define MSSPLL_REFDIV_SHIFT	0x08u
27 #define MSSPLL_REFDIV_WIDTH	0x06u
28 #define MSSPLL_POSTDIV02_SHIFT	0x08u
29 #define MSSPLL_POSTDIV13_SHIFT	0x18u
30 #define MSSPLL_POSTDIV_WIDTH	0x07u
31 #define MSSPLL_FIXED_DIV	4u
32 
33 /*
34  * This clock ID is defined here, rather than the binding headers, as it is an
35  * internal clock only, and therefore has no consumers in other peripheral
36  * blocks.
37  */
38 #define CLK_MSSPLL_INTERNAL	38u
39 
40 struct mpfs_clock_data {
41 	struct device *dev;
42 	void __iomem *base;
43 	void __iomem *msspll_base;
44 	struct clk_hw_onecell_data hw_data;
45 };
46 
47 struct mpfs_msspll_hw_clock {
48 	void __iomem *base;
49 	struct clk_hw hw;
50 	struct clk_init_data init;
51 	unsigned int id;
52 	u32 reg_offset;
53 	u32 shift;
54 	u32 width;
55 	u32 flags;
56 };
57 
58 #define to_mpfs_msspll_clk(_hw) container_of(_hw, struct mpfs_msspll_hw_clock, hw)
59 
60 struct mpfs_msspll_out_hw_clock {
61 	void __iomem *base;
62 	struct clk_divider output;
63 	struct clk_init_data init;
64 	unsigned int id;
65 	u32 reg_offset;
66 };
67 
68 #define to_mpfs_msspll_out_clk(_hw) container_of(_hw, struct mpfs_msspll_out_hw_clock, hw)
69 
70 struct mpfs_cfg_hw_clock {
71 	struct clk_divider cfg;
72 	struct clk_init_data init;
73 	unsigned int id;
74 	u32 reg_offset;
75 };
76 
77 struct mpfs_periph_hw_clock {
78 	struct clk_gate periph;
79 	unsigned int id;
80 };
81 
82 /*
83  * mpfs_clk_lock prevents anything else from writing to the
84  * mpfs clk block while a software locked register is being written.
85  */
86 static DEFINE_SPINLOCK(mpfs_clk_lock);
87 
88 static const struct clk_parent_data mpfs_ext_ref[] = {
89 	{ .index = 0 },
90 };
91 
92 static const struct clk_div_table mpfs_div_cpu_axi_table[] = {
93 	{ 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
94 	{ 0, 0 }
95 };
96 
97 static const struct clk_div_table mpfs_div_ahb_table[] = {
98 	{ 1, 2 }, { 2, 4}, { 3, 8 },
99 	{ 0, 0 }
100 };
101 
102 /*
103  * The only two supported reference clock frequencies for the PolarFire SoC are
104  * 100 and 125 MHz, as the rtc reference is required to be 1 MHz.
105  * It therefore only needs to have divider table entries corresponding to
106  * divide by 100 and 125.
107  */
108 static const struct clk_div_table mpfs_div_rtcref_table[] = {
109 	{ 100, 100 }, { 125, 125 },
110 	{ 0, 0 }
111 };
112 
113 /*
114  * MSS PLL internal clock
115  */
116 
mpfs_clk_msspll_recalc_rate(struct clk_hw * hw,unsigned long prate)117 static unsigned long mpfs_clk_msspll_recalc_rate(struct clk_hw *hw, unsigned long prate)
118 {
119 	struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
120 	void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
121 	void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
122 	u32 mult, ref_div;
123 
124 	mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
125 	mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
126 	ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
127 	ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);
128 
129 	return prate * mult / (ref_div * MSSPLL_FIXED_DIV);
130 }
131 
132 static const struct clk_ops mpfs_clk_msspll_ops = {
133 	.recalc_rate = mpfs_clk_msspll_recalc_rate,
134 };
135 
136 #define CLK_PLL(_id, _name, _parent, _shift, _width, _flags, _offset) {			\
137 	.id = _id,									\
138 	.flags = _flags,								\
139 	.shift = _shift,								\
140 	.width = _width,								\
141 	.reg_offset = _offset,								\
142 	.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_msspll_ops, 0),	\
143 }
144 
145 static struct mpfs_msspll_hw_clock mpfs_msspll_clks[] = {
146 	CLK_PLL(CLK_MSSPLL_INTERNAL, "clk_msspll_internal", mpfs_ext_ref, MSSPLL_FBDIV_SHIFT,
147 		MSSPLL_FBDIV_WIDTH, 0, REG_MSSPLL_SSCG_2_CR),
148 };
149 
mpfs_clk_register_mssplls(struct device * dev,struct mpfs_msspll_hw_clock * msspll_hws,unsigned int num_clks,struct mpfs_clock_data * data)150 static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_clock *msspll_hws,
151 				     unsigned int num_clks, struct mpfs_clock_data *data)
152 {
153 	unsigned int i;
154 	int ret;
155 
156 	for (i = 0; i < num_clks; i++) {
157 		struct mpfs_msspll_hw_clock *msspll_hw = &msspll_hws[i];
158 
159 		msspll_hw->base = data->msspll_base;
160 		ret = devm_clk_hw_register(dev, &msspll_hw->hw);
161 		if (ret)
162 			return dev_err_probe(dev, ret, "failed to register msspll id: %d\n",
163 					     CLK_MSSPLL_INTERNAL);
164 
165 		data->hw_data.hws[msspll_hw->id] = &msspll_hw->hw;
166 	}
167 
168 	return 0;
169 }
170 
171 /*
172  * MSS PLL output clocks
173  */
174 
175 #define CLK_PLL_OUT(_id, _name, _parent, _flags, _shift, _width, _offset) {	\
176 	.id = _id,								\
177 	.output.shift = _shift,							\
178 	.output.width = _width,							\
179 	.output.table = NULL,							\
180 	.reg_offset = _offset,							\
181 	.output.flags = _flags,							\
182 	.output.hw.init = CLK_HW_INIT(_name, _parent, &clk_divider_ops, 0),	\
183 	.output.lock = &mpfs_clk_lock,						\
184 }
185 
186 static struct mpfs_msspll_out_hw_clock mpfs_msspll_out_clks[] = {
187 	CLK_PLL_OUT(CLK_MSSPLL0, "clk_msspll", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
188 		    MSSPLL_POSTDIV02_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV01_CR),
189 	CLK_PLL_OUT(CLK_MSSPLL1, "clk_msspll1", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
190 		    MSSPLL_POSTDIV13_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV01_CR),
191 	CLK_PLL_OUT(CLK_MSSPLL2, "clk_msspll2", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
192 		    MSSPLL_POSTDIV02_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV23_CR),
193 	CLK_PLL_OUT(CLK_MSSPLL3, "clk_msspll3", "clk_msspll_internal", CLK_DIVIDER_ONE_BASED,
194 		    MSSPLL_POSTDIV13_SHIFT, MSSPLL_POSTDIV_WIDTH, REG_MSSPLL_POSTDIV23_CR),
195 };
196 
mpfs_clk_register_msspll_outs(struct device * dev,struct mpfs_msspll_out_hw_clock * msspll_out_hws,unsigned int num_clks,struct mpfs_clock_data * data)197 static int mpfs_clk_register_msspll_outs(struct device *dev,
198 					 struct mpfs_msspll_out_hw_clock *msspll_out_hws,
199 					 unsigned int num_clks, struct mpfs_clock_data *data)
200 {
201 	unsigned int i;
202 	int ret;
203 
204 	for (i = 0; i < num_clks; i++) {
205 		struct mpfs_msspll_out_hw_clock *msspll_out_hw = &msspll_out_hws[i];
206 
207 		msspll_out_hw->output.reg = data->msspll_base + msspll_out_hw->reg_offset;
208 		ret = devm_clk_hw_register(dev, &msspll_out_hw->output.hw);
209 		if (ret)
210 			return dev_err_probe(dev, ret, "failed to register msspll out id: %d\n",
211 					     msspll_out_hw->id);
212 
213 		data->hw_data.hws[msspll_out_hw->id] = &msspll_out_hw->output.hw;
214 	}
215 
216 	return 0;
217 }
218 
219 /*
220  * "CFG" clocks
221  */
222 
223 #define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags, _offset) {		\
224 	.id = _id,									\
225 	.cfg.shift = _shift,								\
226 	.cfg.width = _width,								\
227 	.cfg.table = _table,								\
228 	.reg_offset = _offset,								\
229 	.cfg.flags = _flags,								\
230 	.cfg.hw.init = CLK_HW_INIT(_name, _parent, &clk_divider_ops, 0),		\
231 	.cfg.lock = &mpfs_clk_lock,							\
232 }
233 
234 #define CLK_CPU_OFFSET		0u
235 #define CLK_AXI_OFFSET		1u
236 #define CLK_AHB_OFFSET		2u
237 #define CLK_RTCREF_OFFSET	3u
238 
239 static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
240 	CLK_CFG(CLK_CPU, "clk_cpu", "clk_msspll", 0, 2, mpfs_div_cpu_axi_table, 0,
241 		REG_CLOCK_CONFIG_CR),
242 	CLK_CFG(CLK_AXI, "clk_axi", "clk_msspll", 2, 2, mpfs_div_cpu_axi_table, 0,
243 		REG_CLOCK_CONFIG_CR),
244 	CLK_CFG(CLK_AHB, "clk_ahb", "clk_msspll", 4, 2, mpfs_div_ahb_table, 0,
245 		REG_CLOCK_CONFIG_CR),
246 	{
247 		.id = CLK_RTCREF,
248 		.cfg.shift = 0,
249 		.cfg.width = 12,
250 		.cfg.table = mpfs_div_rtcref_table,
251 		.reg_offset = REG_RTC_CLOCK_CR,
252 		.cfg.flags = CLK_DIVIDER_ONE_BASED,
253 		.cfg.hw.init =
254 			CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &clk_divider_ops, 0),
255 	}
256 };
257 
mpfs_clk_register_cfgs(struct device * dev,struct mpfs_cfg_hw_clock * cfg_hws,unsigned int num_clks,struct mpfs_clock_data * data)258 static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hws,
259 				  unsigned int num_clks, struct mpfs_clock_data *data)
260 {
261 	unsigned int i, id;
262 	int ret;
263 
264 	for (i = 0; i < num_clks; i++) {
265 		struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i];
266 
267 		cfg_hw->cfg.reg = data->base + cfg_hw->reg_offset;
268 		ret = devm_clk_hw_register(dev, &cfg_hw->cfg.hw);
269 		if (ret)
270 			return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
271 					     cfg_hw->id);
272 
273 		id = cfg_hw->id;
274 		data->hw_data.hws[id] = &cfg_hw->cfg.hw;
275 	}
276 
277 	return 0;
278 }
279 
280 /*
281  * peripheral clocks - devices connected to axi or ahb buses.
282  */
283 
284 #define CLK_PERIPH(_id, _name, _parent, _shift, _flags) {			\
285 	.id = _id,								\
286 	.periph.bit_idx = _shift,						\
287 	.periph.hw.init = CLK_HW_INIT_HW(_name, _parent, &clk_gate_ops,		\
288 				  _flags),					\
289 	.periph.lock = &mpfs_clk_lock,						\
290 }
291 
292 #define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT##_OFFSET].cfg.hw)
293 
294 /*
295  * Critical clocks:
296  * - CLK_ENVM: reserved by hart software services (hss) superloop monitor/m mode interrupt
297  *   trap handler
298  * - CLK_MMUART0: reserved by the hss
299  * - CLK_DDRC: provides clock to the ddr subsystem
300  * - CLK_RTC: the onboard RTC's AHB bus clock must be kept running as the rtc will stop
301  *   if the AHB interface clock is disabled
302  * - CLK_FICx: these provide the processor side clocks to the "FIC" (Fabric InterConnect)
303  *   clock domain crossers which provide the interface to the FPGA fabric. Disabling them
304  *   causes the FPGA fabric to go into reset.
305  * - CLK_ATHENA: The athena clock is FIC4, which is reserved for the Athena TeraFire.
306  */
307 
308 static struct mpfs_periph_hw_clock mpfs_periph_clks[] = {
309 	CLK_PERIPH(CLK_ENVM, "clk_periph_envm", PARENT_CLK(AHB), 0, CLK_IS_CRITICAL),
310 	CLK_PERIPH(CLK_MAC0, "clk_periph_mac0", PARENT_CLK(AHB), 1, 0),
311 	CLK_PERIPH(CLK_MAC1, "clk_periph_mac1", PARENT_CLK(AHB), 2, 0),
312 	CLK_PERIPH(CLK_MMC, "clk_periph_mmc", PARENT_CLK(AHB), 3, 0),
313 	CLK_PERIPH(CLK_TIMER, "clk_periph_timer", PARENT_CLK(RTCREF), 4, 0),
314 	CLK_PERIPH(CLK_MMUART0, "clk_periph_mmuart0", PARENT_CLK(AHB), 5, CLK_IS_CRITICAL),
315 	CLK_PERIPH(CLK_MMUART1, "clk_periph_mmuart1", PARENT_CLK(AHB), 6, 0),
316 	CLK_PERIPH(CLK_MMUART2, "clk_periph_mmuart2", PARENT_CLK(AHB), 7, 0),
317 	CLK_PERIPH(CLK_MMUART3, "clk_periph_mmuart3", PARENT_CLK(AHB), 8, 0),
318 	CLK_PERIPH(CLK_MMUART4, "clk_periph_mmuart4", PARENT_CLK(AHB), 9, 0),
319 	CLK_PERIPH(CLK_SPI0, "clk_periph_spi0", PARENT_CLK(AHB), 10, 0),
320 	CLK_PERIPH(CLK_SPI1, "clk_periph_spi1", PARENT_CLK(AHB), 11, 0),
321 	CLK_PERIPH(CLK_I2C0, "clk_periph_i2c0", PARENT_CLK(AHB), 12, 0),
322 	CLK_PERIPH(CLK_I2C1, "clk_periph_i2c1", PARENT_CLK(AHB), 13, 0),
323 	CLK_PERIPH(CLK_CAN0, "clk_periph_can0", PARENT_CLK(AHB), 14, 0),
324 	CLK_PERIPH(CLK_CAN1, "clk_periph_can1", PARENT_CLK(AHB), 15, 0),
325 	CLK_PERIPH(CLK_USB, "clk_periph_usb", PARENT_CLK(AHB), 16, 0),
326 	CLK_PERIPH(CLK_RTC, "clk_periph_rtc", PARENT_CLK(AHB), 18, CLK_IS_CRITICAL),
327 	CLK_PERIPH(CLK_QSPI, "clk_periph_qspi", PARENT_CLK(AHB), 19, 0),
328 	CLK_PERIPH(CLK_GPIO0, "clk_periph_gpio0", PARENT_CLK(AHB), 20, 0),
329 	CLK_PERIPH(CLK_GPIO1, "clk_periph_gpio1", PARENT_CLK(AHB), 21, 0),
330 	CLK_PERIPH(CLK_GPIO2, "clk_periph_gpio2", PARENT_CLK(AHB), 22, 0),
331 	CLK_PERIPH(CLK_DDRC, "clk_periph_ddrc", PARENT_CLK(AHB), 23, CLK_IS_CRITICAL),
332 	CLK_PERIPH(CLK_FIC0, "clk_periph_fic0", PARENT_CLK(AXI), 24, CLK_IS_CRITICAL),
333 	CLK_PERIPH(CLK_FIC1, "clk_periph_fic1", PARENT_CLK(AXI), 25, CLK_IS_CRITICAL),
334 	CLK_PERIPH(CLK_FIC2, "clk_periph_fic2", PARENT_CLK(AXI), 26, CLK_IS_CRITICAL),
335 	CLK_PERIPH(CLK_FIC3, "clk_periph_fic3", PARENT_CLK(AXI), 27, CLK_IS_CRITICAL),
336 	CLK_PERIPH(CLK_ATHENA, "clk_periph_athena", PARENT_CLK(AXI), 28, CLK_IS_CRITICAL),
337 	CLK_PERIPH(CLK_CFM, "clk_periph_cfm", PARENT_CLK(AHB), 29, 0),
338 };
339 
mpfs_clk_register_periphs(struct device * dev,struct mpfs_periph_hw_clock * periph_hws,int num_clks,struct mpfs_clock_data * data)340 static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_clock *periph_hws,
341 				     int num_clks, struct mpfs_clock_data *data)
342 {
343 	unsigned int i, id;
344 	int ret;
345 
346 	for (i = 0; i < num_clks; i++) {
347 		struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i];
348 
349 		periph_hw->periph.reg = data->base + REG_SUBBLK_CLOCK_CR;
350 		ret = devm_clk_hw_register(dev, &periph_hw->periph.hw);
351 		if (ret)
352 			return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
353 					     periph_hw->id);
354 
355 		id = periph_hws[i].id;
356 		data->hw_data.hws[id] = &periph_hw->periph.hw;
357 	}
358 
359 	return 0;
360 }
361 
mpfs_clk_probe(struct platform_device * pdev)362 static int mpfs_clk_probe(struct platform_device *pdev)
363 {
364 	struct device *dev = &pdev->dev;
365 	struct mpfs_clock_data *clk_data;
366 	unsigned int num_clks;
367 	int ret;
368 
369 	/* CLK_RESERVED is not part of clock arrays, so add 1 */
370 	num_clks = ARRAY_SIZE(mpfs_msspll_clks) + ARRAY_SIZE(mpfs_msspll_out_clks)
371 		   + ARRAY_SIZE(mpfs_cfg_clks)  + ARRAY_SIZE(mpfs_periph_clks) + 1;
372 
373 	clk_data = devm_kzalloc(dev, struct_size(clk_data, hw_data.hws, num_clks), GFP_KERNEL);
374 	if (!clk_data)
375 		return -ENOMEM;
376 
377 	clk_data->base = devm_platform_ioremap_resource(pdev, 0);
378 	if (IS_ERR(clk_data->base))
379 		return PTR_ERR(clk_data->base);
380 
381 	clk_data->msspll_base = devm_platform_ioremap_resource(pdev, 1);
382 	if (IS_ERR(clk_data->msspll_base))
383 		return PTR_ERR(clk_data->msspll_base);
384 
385 	clk_data->hw_data.num = num_clks;
386 	clk_data->dev = dev;
387 	dev_set_drvdata(dev, clk_data);
388 
389 	ret = mpfs_clk_register_mssplls(dev, mpfs_msspll_clks, ARRAY_SIZE(mpfs_msspll_clks),
390 					clk_data);
391 	if (ret)
392 		return ret;
393 
394 	ret = mpfs_clk_register_msspll_outs(dev, mpfs_msspll_out_clks,
395 					    ARRAY_SIZE(mpfs_msspll_out_clks),
396 					    clk_data);
397 	if (ret)
398 		return ret;
399 
400 	ret = mpfs_clk_register_cfgs(dev, mpfs_cfg_clks, ARRAY_SIZE(mpfs_cfg_clks), clk_data);
401 	if (ret)
402 		return ret;
403 
404 	ret = mpfs_clk_register_periphs(dev, mpfs_periph_clks, ARRAY_SIZE(mpfs_periph_clks),
405 					clk_data);
406 	if (ret)
407 		return ret;
408 
409 	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clk_data->hw_data);
410 	if (ret)
411 		return ret;
412 
413 	return mpfs_reset_controller_register(dev, clk_data->base + REG_SUBBLK_RESET_CR);
414 }
415 
416 static const struct of_device_id mpfs_clk_of_match_table[] = {
417 	{ .compatible = "microchip,mpfs-clkcfg", },
418 	{}
419 };
420 MODULE_DEVICE_TABLE(of, mpfs_clk_of_match_table);
421 
422 static struct platform_driver mpfs_clk_driver = {
423 	.probe = mpfs_clk_probe,
424 	.driver	= {
425 		.name = "microchip-mpfs-clkcfg",
426 		.of_match_table = mpfs_clk_of_match_table,
427 	},
428 };
429 
clk_mpfs_init(void)430 static int __init clk_mpfs_init(void)
431 {
432 	return platform_driver_register(&mpfs_clk_driver);
433 }
434 core_initcall(clk_mpfs_init);
435 
clk_mpfs_exit(void)436 static void __exit clk_mpfs_exit(void)
437 {
438 	platform_driver_unregister(&mpfs_clk_driver);
439 }
440 module_exit(clk_mpfs_exit);
441 
442 MODULE_DESCRIPTION("Microchip PolarFire SoC Clock Driver");
443 MODULE_AUTHOR("Padmarao Begari <padmarao.begari@microchip.com>");
444 MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
445 MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
446 MODULE_IMPORT_NS("MCHP_CLK_MPFS");
447