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