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 
8 #include "stratix10-clk.h"
9 #include "clk.h"
10 
11 /* Clock Manager offsets */
12 #define CLK_MGR_PLL_CLK_SRC_SHIFT	16
13 #define CLK_MGR_PLL_CLK_SRC_MASK	0x3
14 
15 /* PLL Clock enable bits */
16 #define SOCFPGA_PLL_POWER		0
17 #define SOCFPGA_PLL_RESET_MASK		0x2
18 #define SOCFPGA_PLL_REFDIV_MASK		0x00003F00
19 #define SOCFPGA_PLL_REFDIV_SHIFT	8
20 #define SOCFPGA_PLL_MDIV_MASK		0xFF000000
21 #define SOCFPGA_PLL_MDIV_SHIFT		24
22 #define SWCTRLBTCLKSEL_MASK		0x200
23 #define SWCTRLBTCLKSEL_SHIFT		9
24 
25 #define SOCFPGA_BOOT_CLK		"boot_clk"
26 
27 #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
28 
clk_pll_recalc_rate(struct clk_hw * hwclk,unsigned long parent_rate)29 static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
30 					 unsigned long parent_rate)
31 {
32 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
33 	unsigned long mdiv;
34 	unsigned long refdiv;
35 	unsigned long reg;
36 	unsigned long long vco_freq;
37 
38 	/* read VCO1 reg for numerator and denominator */
39 	reg = readl(socfpgaclk->hw.reg);
40 	refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
41 
42 	vco_freq = parent_rate;
43 	do_div(vco_freq, refdiv);
44 
45 	/* Read mdiv and fdiv from the fdbck register */
46 	reg = readl(socfpgaclk->hw.reg + 0x4);
47 	mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT;
48 	vco_freq = (unsigned long long)vco_freq * (mdiv + 6);
49 
50 	return (unsigned long)vco_freq;
51 }
52 
clk_boot_clk_recalc_rate(struct clk_hw * hwclk,unsigned long parent_rate)53 static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk,
54 					 unsigned long parent_rate)
55 {
56 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
57 	u32 div = 1;
58 
59 	div = ((readl(socfpgaclk->hw.reg) &
60 		SWCTRLBTCLKSEL_MASK) >>
61 		SWCTRLBTCLKSEL_SHIFT);
62 	div += 1;
63 	return parent_rate /= div;
64 }
65 
66 
clk_pll_get_parent(struct clk_hw * hwclk)67 static u8 clk_pll_get_parent(struct clk_hw *hwclk)
68 {
69 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
70 	u32 pll_src;
71 
72 	pll_src = readl(socfpgaclk->hw.reg);
73 	return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
74 		CLK_MGR_PLL_CLK_SRC_MASK;
75 }
76 
clk_boot_get_parent(struct clk_hw * hwclk)77 static u8 clk_boot_get_parent(struct clk_hw *hwclk)
78 {
79 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
80 	u32 pll_src;
81 
82 	pll_src = readl(socfpgaclk->hw.reg);
83 	return (pll_src >> SWCTRLBTCLKSEL_SHIFT) &
84 		SWCTRLBTCLKSEL_MASK;
85 }
86 
clk_pll_prepare(struct clk_hw * hwclk)87 static int clk_pll_prepare(struct clk_hw *hwclk)
88 {
89 	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
90 	u32 reg;
91 
92 	/* Bring PLL out of reset */
93 	reg = readl(socfpgaclk->hw.reg);
94 	reg |= SOCFPGA_PLL_RESET_MASK;
95 	writel(reg, socfpgaclk->hw.reg);
96 
97 	return 0;
98 }
99 
100 static struct clk_ops clk_pll_ops = {
101 	.recalc_rate = clk_pll_recalc_rate,
102 	.get_parent = clk_pll_get_parent,
103 	.prepare = clk_pll_prepare,
104 };
105 
106 static struct clk_ops clk_boot_ops = {
107 	.recalc_rate = clk_boot_clk_recalc_rate,
108 	.get_parent = clk_boot_get_parent,
109 	.prepare = clk_pll_prepare,
110 };
111 
s10_register_pll(const char * name,const char * const * parent_names,u8 num_parents,unsigned long flags,void __iomem * reg,unsigned long offset)112 struct clk *s10_register_pll(const char *name, const char * const *parent_names,
113 				    u8 num_parents, unsigned long flags,
114 				    void __iomem *reg, unsigned long offset)
115 {
116 	struct clk *clk;
117 	struct socfpga_pll *pll_clk;
118 	struct clk_init_data init;
119 
120 	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
121 	if (WARN_ON(!pll_clk))
122 		return NULL;
123 
124 	pll_clk->hw.reg = reg + offset;
125 
126 	if (streq(name, SOCFPGA_BOOT_CLK))
127 		init.ops = &clk_boot_ops;
128 	else
129 		init.ops = &clk_pll_ops;
130 
131 	init.name = name;
132 	init.flags = flags;
133 
134 	init.num_parents = num_parents;
135 	init.parent_names = parent_names;
136 	pll_clk->hw.hw.init = &init;
137 
138 	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
139 	clk_pll_ops.enable = clk_gate_ops.enable;
140 	clk_pll_ops.disable = clk_gate_ops.disable;
141 
142 	clk = clk_register(NULL, &pll_clk->hw.hw);
143 	if (WARN_ON(IS_ERR(clk))) {
144 		kfree(pll_clk);
145 		return NULL;
146 	}
147 	return clk;
148 }
149