summaryrefslogtreecommitdiffstats
path: root/drivers/clk/bcm
diff options
context:
space:
mode:
authorRay Jui <rjui@broadcom.com>2015-05-05 14:13:19 -0400
committerMichael Turquette <mturquette@baylibre.com>2015-06-18 15:36:38 -0400
commit5fe225c105fd54debae1699ec0f6aef1e73376d0 (patch)
tree0bb5a968604a4ca1584828b6d7670228d8b86771 /drivers/clk/bcm
parent476276d69d84edd4f5de9711f55c810dfc69c26c (diff)
clk: iproc: add initial common clock support
This adds basic and generic support for various iProc PLLs and clocks including the ARMPLL, GENPLL, LCPLL, MIPIPLL, and ASIU clocks. SoCs under the iProc architecture can define their specific register offsets and clock parameters for their PLL and clock controllers. These parameters can be passed as arugments into the generic iProc PLL and clock setup functions Derived from code originally provided by Jonathan Richardson <jonathar@broadcom.com> Signed-off-by: Ray Jui <rjui@broadcom.com> Reviewed-by: Scott Branden <sbranden@broadcom.com> Signed-off-by: Michael Turquette <mturquette@baylibre.com>
Diffstat (limited to 'drivers/clk/bcm')
-rw-r--r--drivers/clk/bcm/Kconfig9
-rw-r--r--drivers/clk/bcm/Makefile1
-rw-r--r--drivers/clk/bcm/clk-iproc-armpll.c282
-rw-r--r--drivers/clk/bcm/clk-iproc-asiu.c276
-rw-r--r--drivers/clk/bcm/clk-iproc-pll.c716
-rw-r--r--drivers/clk/bcm/clk-iproc.h178
6 files changed, 1462 insertions, 0 deletions
diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
index 75506e53075b..88febf53b276 100644
--- a/drivers/clk/bcm/Kconfig
+++ b/drivers/clk/bcm/Kconfig
@@ -7,3 +7,12 @@ config CLK_BCM_KONA
7 Enable common clock framework support for Broadcom SoCs 7 Enable common clock framework support for Broadcom SoCs
8 using "Kona" style clock control units, including those 8 using "Kona" style clock control units, including those
9 in the BCM281xx and BCM21664 families. 9 in the BCM281xx and BCM21664 families.
10
11config COMMON_CLK_IPROC
12 bool "Broadcom iProc clock support"
13 depends on ARCH_BCM_IPROC
14 depends on COMMON_CLK
15 default ARCH_BCM_IPROC
16 help
17 Enable common clock framework support for Broadcom SoCs
18 based on the iProc architecture
diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
index 6297d05a9a10..0facbbc5652c 100644
--- a/drivers/clk/bcm/Makefile
+++ b/drivers/clk/bcm/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
2obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o 2obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
3obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o 3obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
4obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o 4obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
5obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
diff --git a/drivers/clk/bcm/clk-iproc-armpll.c b/drivers/clk/bcm/clk-iproc-armpll.c
new file mode 100644
index 000000000000..a196ee28a17a
--- /dev/null
+++ b/drivers/clk/bcm/clk-iproc-armpll.c
@@ -0,0 +1,282 @@
1/*
2 * Copyright (C) 2014 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/err.h>
17#include <linux/clk-provider.h>
18#include <linux/io.h>
19#include <linux/of.h>
20#include <linux/clkdev.h>
21#include <linux/of_address.h>
22
23#define IPROC_CLK_MAX_FREQ_POLICY 0x3
24#define IPROC_CLK_POLICY_FREQ_OFFSET 0x008
25#define IPROC_CLK_POLICY_FREQ_POLICY_FREQ_SHIFT 8
26#define IPROC_CLK_POLICY_FREQ_POLICY_FREQ_MASK 0x7
27
28#define IPROC_CLK_PLLARMA_OFFSET 0xc00
29#define IPROC_CLK_PLLARMA_LOCK_SHIFT 28
30#define IPROC_CLK_PLLARMA_PDIV_SHIFT 24
31#define IPROC_CLK_PLLARMA_PDIV_MASK 0xf
32#define IPROC_CLK_PLLARMA_NDIV_INT_SHIFT 8
33#define IPROC_CLK_PLLARMA_NDIV_INT_MASK 0x3ff
34
35#define IPROC_CLK_PLLARMB_OFFSET 0xc04
36#define IPROC_CLK_PLLARMB_NDIV_FRAC_MASK 0xfffff
37
38#define IPROC_CLK_PLLARMC_OFFSET 0xc08
39#define IPROC_CLK_PLLARMC_BYPCLK_EN_SHIFT 8
40#define IPROC_CLK_PLLARMC_MDIV_MASK 0xff
41
42#define IPROC_CLK_PLLARMCTL5_OFFSET 0xc20
43#define IPROC_CLK_PLLARMCTL5_H_MDIV_MASK 0xff
44
45#define IPROC_CLK_PLLARM_OFFSET_OFFSET 0xc24
46#define IPROC_CLK_PLLARM_SW_CTL_SHIFT 29
47#define IPROC_CLK_PLLARM_NDIV_INT_OFFSET_SHIFT 20
48#define IPROC_CLK_PLLARM_NDIV_INT_OFFSET_MASK 0xff
49#define IPROC_CLK_PLLARM_NDIV_FRAC_OFFSET_MASK 0xfffff
50
51#define IPROC_CLK_ARM_DIV_OFFSET 0xe00
52#define IPROC_CLK_ARM_DIV_PLL_SELECT_OVERRIDE_SHIFT 4
53#define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK 0xf
54
55#define IPROC_CLK_POLICY_DBG_OFFSET 0xec0
56#define IPROC_CLK_POLICY_DBG_ACT_FREQ_SHIFT 12
57#define IPROC_CLK_POLICY_DBG_ACT_FREQ_MASK 0x7
58
59enum iproc_arm_pll_fid {
60 ARM_PLL_FID_CRYSTAL_CLK = 0,
61 ARM_PLL_FID_SYS_CLK = 2,
62 ARM_PLL_FID_CH0_SLOW_CLK = 6,
63 ARM_PLL_FID_CH1_FAST_CLK = 7
64};
65
66struct iproc_arm_pll {
67 struct clk_hw hw;
68 void __iomem *base;
69 unsigned long rate;
70};
71
72#define to_iproc_arm_pll(hw) container_of(hw, struct iproc_arm_pll, hw)
73
74static unsigned int __get_fid(struct iproc_arm_pll *pll)
75{
76 u32 val;
77 unsigned int policy, fid, active_fid;
78
79 val = readl(pll->base + IPROC_CLK_ARM_DIV_OFFSET);
80 if (val & (1 << IPROC_CLK_ARM_DIV_PLL_SELECT_OVERRIDE_SHIFT))
81 policy = val & IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK;
82 else
83 policy = 0;
84
85 /* something is seriously wrong */
86 BUG_ON(policy > IPROC_CLK_MAX_FREQ_POLICY);
87
88 val = readl(pll->base + IPROC_CLK_POLICY_FREQ_OFFSET);
89 fid = (val >> (IPROC_CLK_POLICY_FREQ_POLICY_FREQ_SHIFT * policy)) &
90 IPROC_CLK_POLICY_FREQ_POLICY_FREQ_MASK;
91
92 val = readl(pll->base + IPROC_CLK_POLICY_DBG_OFFSET);
93 active_fid = IPROC_CLK_POLICY_DBG_ACT_FREQ_MASK &
94 (val >> IPROC_CLK_POLICY_DBG_ACT_FREQ_SHIFT);
95 if (fid != active_fid) {
96 pr_debug("%s: fid override %u->%u\n", __func__, fid,
97 active_fid);
98 fid = active_fid;
99 }
100
101 pr_debug("%s: active fid: %u\n", __func__, fid);
102
103 return fid;
104}
105
106/*
107 * Determine the mdiv (post divider) based on the frequency ID being used.
108 * There are 4 sources that can be used to derive the output clock rate:
109 * - 25 MHz Crystal
110 * - System clock
111 * - PLL channel 0 (slow clock)
112 * - PLL channel 1 (fast clock)
113 */
114static int __get_mdiv(struct iproc_arm_pll *pll)
115{
116 unsigned int fid;
117 int mdiv;
118 u32 val;
119
120 fid = __get_fid(pll);
121
122 switch (fid) {
123 case ARM_PLL_FID_CRYSTAL_CLK:
124 case ARM_PLL_FID_SYS_CLK:
125 mdiv = 1;
126 break;
127
128 case ARM_PLL_FID_CH0_SLOW_CLK:
129 val = readl(pll->base + IPROC_CLK_PLLARMC_OFFSET);
130 mdiv = val & IPROC_CLK_PLLARMC_MDIV_MASK;
131 if (mdiv == 0)
132 mdiv = 256;
133 break;
134
135 case ARM_PLL_FID_CH1_FAST_CLK:
136 val = readl(pll->base + IPROC_CLK_PLLARMCTL5_OFFSET);
137 mdiv = val & IPROC_CLK_PLLARMCTL5_H_MDIV_MASK;
138 if (mdiv == 0)
139 mdiv = 256;
140 break;
141
142 default:
143 mdiv = -EFAULT;
144 }
145
146 return mdiv;
147}
148
149static unsigned int __get_ndiv(struct iproc_arm_pll *pll)
150{
151 u32 val;
152 unsigned int ndiv_int, ndiv_frac, ndiv;
153
154 val = readl(pll->base + IPROC_CLK_PLLARM_OFFSET_OFFSET);
155 if (val & (1 << IPROC_CLK_PLLARM_SW_CTL_SHIFT)) {
156 /*
157 * offset mode is active. Read the ndiv from the PLLARM OFFSET
158 * register
159 */
160 ndiv_int = (val >> IPROC_CLK_PLLARM_NDIV_INT_OFFSET_SHIFT) &
161 IPROC_CLK_PLLARM_NDIV_INT_OFFSET_MASK;
162 if (ndiv_int == 0)
163 ndiv_int = 256;
164
165 ndiv_frac = val & IPROC_CLK_PLLARM_NDIV_FRAC_OFFSET_MASK;
166 } else {
167 /* offset mode not active */
168 val = readl(pll->base + IPROC_CLK_PLLARMA_OFFSET);
169 ndiv_int = (val >> IPROC_CLK_PLLARMA_NDIV_INT_SHIFT) &
170 IPROC_CLK_PLLARMA_NDIV_INT_MASK;
171 if (ndiv_int == 0)
172 ndiv_int = 1024;
173
174 val = readl(pll->base + IPROC_CLK_PLLARMB_OFFSET);
175 ndiv_frac = val & IPROC_CLK_PLLARMB_NDIV_FRAC_MASK;
176 }
177
178 ndiv = (ndiv_int << 20) | ndiv_frac;
179
180 return ndiv;
181}
182
183/*
184 * The output frequency of the ARM PLL is calculated based on the ARM PLL
185 * divider values:
186 * pdiv = ARM PLL pre-divider
187 * ndiv = ARM PLL multiplier
188 * mdiv = ARM PLL post divider
189 *
190 * The frequency is calculated by:
191 * ((ndiv * parent clock rate) / pdiv) / mdiv
192 */
193static unsigned long iproc_arm_pll_recalc_rate(struct clk_hw *hw,
194 unsigned long parent_rate)
195{
196 struct iproc_arm_pll *pll = to_iproc_arm_pll(hw);
197 u32 val;
198 int mdiv;
199 u64 ndiv;
200 unsigned int pdiv;
201
202 /* in bypass mode, use parent rate */
203 val = readl(pll->base + IPROC_CLK_PLLARMC_OFFSET);
204 if (val & (1 << IPROC_CLK_PLLARMC_BYPCLK_EN_SHIFT)) {
205 pll->rate = parent_rate;
206 return pll->rate;
207 }
208
209 /* PLL needs to be locked */
210 val = readl(pll->base + IPROC_CLK_PLLARMA_OFFSET);
211 if (!(val & (1 << IPROC_CLK_PLLARMA_LOCK_SHIFT))) {
212 pll->rate = 0;
213 return 0;
214 }
215
216 pdiv = (val >> IPROC_CLK_PLLARMA_PDIV_SHIFT) &
217 IPROC_CLK_PLLARMA_PDIV_MASK;
218 if (pdiv == 0)
219 pdiv = 16;
220
221 ndiv = __get_ndiv(pll);
222 mdiv = __get_mdiv(pll);
223 if (mdiv <= 0) {
224 pll->rate = 0;
225 return 0;
226 }
227 pll->rate = (ndiv * parent_rate) >> 20;
228 pll->rate = (pll->rate / pdiv) / mdiv;
229
230 pr_debug("%s: ARM PLL rate: %lu. parent rate: %lu\n", __func__,
231 pll->rate, parent_rate);
232 pr_debug("%s: ndiv_int: %u, pdiv: %u, mdiv: %d\n", __func__,
233 (unsigned int)(ndiv >> 20), pdiv, mdiv);
234
235 return pll->rate;
236}
237
238static const struct clk_ops iproc_arm_pll_ops = {
239 .recalc_rate = iproc_arm_pll_recalc_rate,
240};
241
242void __init iproc_armpll_setup(struct device_node *node)
243{
244 int ret;
245 struct clk *clk;
246 struct iproc_arm_pll *pll;
247 struct clk_init_data init;
248 const char *parent_name;
249
250 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
251 if (WARN_ON(!pll))
252 return;
253
254 pll->base = of_iomap(node, 0);
255 if (WARN_ON(!pll->base))
256 goto err_free_pll;
257
258 init.name = node->name;
259 init.ops = &iproc_arm_pll_ops;
260 init.flags = 0;
261 parent_name = of_clk_get_parent_name(node, 0);
262 init.parent_names = (parent_name ? &parent_name : NULL);
263 init.num_parents = (parent_name ? 1 : 0);
264 pll->hw.init = &init;
265
266 clk = clk_register(NULL, &pll->hw);
267 if (WARN_ON(IS_ERR(clk)))
268 goto err_iounmap;
269
270 ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
271 if (WARN_ON(ret))
272 goto err_clk_unregister;
273
274 return;
275
276err_clk_unregister:
277 clk_unregister(clk);
278err_iounmap:
279 iounmap(pll->base);
280err_free_pll:
281 kfree(pll);
282}
diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c
new file mode 100644
index 000000000000..e19c09cd9645
--- /dev/null
+++ b/drivers/clk/bcm/clk-iproc-asiu.c
@@ -0,0 +1,276 @@
1/*
2 * Copyright (C) 2014 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/err.h>
16#include <linux/clk-provider.h>
17#include <linux/io.h>
18#include <linux/of.h>
19#include <linux/clkdev.h>
20#include <linux/of_address.h>
21#include <linux/delay.h>
22
23#include "clk-iproc.h"
24
25struct iproc_asiu;
26
27struct iproc_asiu_clk {
28 struct clk_hw hw;
29 const char *name;
30 struct iproc_asiu *asiu;
31 unsigned long rate;
32 struct iproc_asiu_div div;
33 struct iproc_asiu_gate gate;
34};
35
36struct iproc_asiu {
37 void __iomem *div_base;
38 void __iomem *gate_base;
39
40 struct clk_onecell_data clk_data;
41 struct iproc_asiu_clk *clks;
42};
43
44#define to_asiu_clk(hw) container_of(hw, struct iproc_asiu_clk, hw)
45
46static int iproc_asiu_clk_enable(struct clk_hw *hw)
47{
48 struct iproc_asiu_clk *clk = to_asiu_clk(hw);
49 struct iproc_asiu *asiu = clk->asiu;
50 u32 val;
51
52 /* some clocks at the ASIU level are always enabled */
53 if (clk->gate.offset == IPROC_CLK_INVALID_OFFSET)
54 return 0;
55
56 val = readl(asiu->gate_base + clk->gate.offset);
57 val |= (1 << clk->gate.en_shift);
58 writel(val, asiu->gate_base + clk->gate.offset);
59
60 return 0;
61}
62
63static void iproc_asiu_clk_disable(struct clk_hw *hw)
64{
65 struct iproc_asiu_clk *clk = to_asiu_clk(hw);
66 struct iproc_asiu *asiu = clk->asiu;
67 u32 val;
68
69 /* some clocks at the ASIU level are always enabled */
70 if (clk->gate.offset == IPROC_CLK_INVALID_OFFSET)
71 return;
72
73 val = readl(asiu->gate_base + clk->gate.offset);
74 val &= ~(1 << clk->gate.en_shift);
75 writel(val, asiu->gate_base + clk->gate.offset);
76}
77
78static unsigned long iproc_asiu_clk_recalc_rate(struct clk_hw *hw,
79 unsigned long parent_rate)
80{
81 struct iproc_asiu_clk *clk = to_asiu_clk(hw);
82 struct iproc_asiu *asiu = clk->asiu;
83 u32 val;
84 unsigned int div_h, div_l;
85
86 if (parent_rate == 0) {
87 clk->rate = 0;
88 return 0;
89 }
90
91 /* if clock divisor is not enabled, simply return parent rate */
92 val = readl(asiu->div_base + clk->div.offset);
93 if ((val & (1 << clk->div.en_shift)) == 0) {
94 clk->rate = parent_rate;
95 return parent_rate;
96 }
97
98 /* clock rate = parent rate / (high_div + 1) + (low_div + 1) */
99 div_h = (val >> clk->div.high_shift) & bit_mask(clk->div.high_width);
100 div_h++;
101 div_l = (val >> clk->div.low_shift) & bit_mask(clk->div.low_width);
102 div_l++;
103
104 clk->rate = parent_rate / (div_h + div_l);
105 pr_debug("%s: rate: %lu. parent rate: %lu div_h: %u div_l: %u\n",
106 __func__, clk->rate, parent_rate, div_h, div_l);
107
108 return clk->rate;
109}
110
111static long iproc_asiu_clk_round_rate(struct clk_hw *hw, unsigned long rate,
112 unsigned long *parent_rate)
113{
114 unsigned int div;
115
116 if (rate == 0 || *parent_rate == 0)
117 return -EINVAL;
118
119 if (rate == *parent_rate)
120 return *parent_rate;
121
122 div = DIV_ROUND_UP(*parent_rate, rate);
123 if (div < 2)
124 return *parent_rate;
125
126 return *parent_rate / div;
127}
128
129static int iproc_asiu_clk_set_rate(struct clk_hw *hw, unsigned long rate,
130 unsigned long parent_rate)
131{
132 struct iproc_asiu_clk *clk = to_asiu_clk(hw);
133 struct iproc_asiu *asiu = clk->asiu;
134 unsigned int div, div_h, div_l;
135 u32 val;
136
137 if (rate == 0 || parent_rate == 0)
138 return -EINVAL;
139
140 /* simply disable the divisor if one wants the same rate as parent */
141 if (rate == parent_rate) {
142 val = readl(asiu->div_base + clk->div.offset);
143 val &= ~(1 << clk->div.en_shift);
144 writel(val, asiu->div_base + clk->div.offset);
145 return 0;
146 }
147
148 div = DIV_ROUND_UP(parent_rate, rate);
149 if (div < 2)
150 return -EINVAL;
151
152 div_h = div_l = div >> 1;
153 div_h--;
154 div_l--;
155
156 val = readl(asiu->div_base + clk->div.offset);
157 val |= 1 << clk->div.en_shift;
158 if (div_h) {
159 val &= ~(bit_mask(clk->div.high_width)
160 << clk->div.high_shift);
161 val |= div_h << clk->div.high_shift;
162 } else {
163 val &= ~(bit_mask(clk->div.high_width)
164 << clk->div.high_shift);
165 }
166 if (div_l) {
167 val &= ~(bit_mask(clk->div.low_width) << clk->div.low_shift);
168 val |= div_l << clk->div.low_shift;
169 } else {
170 val &= ~(bit_mask(clk->div.low_width) << clk->div.low_shift);
171 }
172 writel(val, asiu->div_base + clk->div.offset);
173
174 return 0;
175}
176
177static const struct clk_ops iproc_asiu_ops = {
178 .enable = iproc_asiu_clk_enable,
179 .disable = iproc_asiu_clk_disable,
180 .recalc_rate = iproc_asiu_clk_recalc_rate,
181 .round_rate = iproc_asiu_clk_round_rate,
182 .set_rate = iproc_asiu_clk_set_rate,
183};
184
185void __init iproc_asiu_setup(struct device_node *node,
186 const struct iproc_asiu_div *div,
187 const struct iproc_asiu_gate *gate,
188 unsigned int num_clks)
189{
190 int i, ret;
191 struct iproc_asiu *asiu;
192
193 if (WARN_ON(!gate || !div))
194 return;
195
196 asiu = kzalloc(sizeof(*asiu), GFP_KERNEL);
197 if (WARN_ON(!asiu))
198 return;
199
200 asiu->clk_data.clk_num = num_clks;
201 asiu->clk_data.clks = kcalloc(num_clks, sizeof(*asiu->clk_data.clks),
202 GFP_KERNEL);
203 if (WARN_ON(!asiu->clk_data.clks))
204 goto err_clks;
205
206 asiu->clks = kcalloc(num_clks, sizeof(*asiu->clks), GFP_KERNEL);
207 if (WARN_ON(!asiu->clks))
208 goto err_asiu_clks;
209
210 asiu->div_base = of_iomap(node, 0);
211 if (WARN_ON(!asiu->div_base))
212 goto err_iomap_div;
213
214 asiu->gate_base = of_iomap(node, 1);
215 if (WARN_ON(!asiu->gate_base))
216 goto err_iomap_gate;
217
218 for (i = 0; i < num_clks; i++) {
219 struct clk_init_data init;
220 struct clk *clk;
221 const char *parent_name;
222 struct iproc_asiu_clk *asiu_clk;
223 const char *clk_name;
224
225 clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL);
226 if (WARN_ON(!clk_name))
227 goto err_clk_register;
228
229 ret = of_property_read_string_index(node, "clock-output-names",
230 i, &clk_name);
231 if (WARN_ON(ret))
232 goto err_clk_register;
233
234 asiu_clk = &asiu->clks[i];
235 asiu_clk->name = clk_name;
236 asiu_clk->asiu = asiu;
237 asiu_clk->div = div[i];
238 asiu_clk->gate = gate[i];
239 init.name = clk_name;
240 init.ops = &iproc_asiu_ops;
241 init.flags = 0;
242 parent_name = of_clk_get_parent_name(node, 0);
243 init.parent_names = (parent_name ? &parent_name : NULL);
244 init.num_parents = (parent_name ? 1 : 0);
245 asiu_clk->hw.init = &init;
246
247 clk = clk_register(NULL, &asiu_clk->hw);
248 if (WARN_ON(IS_ERR(clk)))
249 goto err_clk_register;
250 asiu->clk_data.clks[i] = clk;
251 }
252
253 ret = of_clk_add_provider(node, of_clk_src_onecell_get,
254 &asiu->clk_data);
255 if (WARN_ON(ret))
256 goto err_clk_register;
257
258 return;
259
260err_clk_register:
261 for (i = 0; i < num_clks; i++)
262 kfree(asiu->clks[i].name);
263 iounmap(asiu->gate_base);
264
265err_iomap_gate:
266 iounmap(asiu->div_base);
267
268err_iomap_div:
269 kfree(asiu->clks);
270
271err_asiu_clks:
272 kfree(asiu->clk_data.clks);
273
274err_clks:
275 kfree(asiu);
276}
diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c
new file mode 100644
index 000000000000..46fb84bc2674
--- /dev/null
+++ b/drivers/clk/bcm/clk-iproc-pll.c
@@ -0,0 +1,716 @@
1/*
2 * Copyright (C) 2014 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/err.h>
16#include <linux/clk-provider.h>
17#include <linux/io.h>
18#include <linux/of.h>
19#include <linux/clkdev.h>
20#include <linux/of_address.h>
21#include <linux/delay.h>
22
23#include "clk-iproc.h"
24
25#define PLL_VCO_HIGH_SHIFT 19
26#define PLL_VCO_LOW_SHIFT 30
27
28/* number of delay loops waiting for PLL to lock */
29#define LOCK_DELAY 100
30
31/* number of VCO frequency bands */
32#define NUM_FREQ_BANDS 8
33
34#define NUM_KP_BANDS 3
35enum kp_band {
36 KP_BAND_MID = 0,
37 KP_BAND_HIGH,
38 KP_BAND_HIGH_HIGH
39};
40
41static const unsigned int kp_table[NUM_KP_BANDS][NUM_FREQ_BANDS] = {
42 { 5, 6, 6, 7, 7, 8, 9, 10 },
43 { 4, 4, 5, 5, 6, 7, 8, 9 },
44 { 4, 5, 5, 6, 7, 8, 9, 10 },
45};
46
47static const unsigned long ref_freq_table[NUM_FREQ_BANDS][2] = {
48 { 10000000, 12500000 },
49 { 12500000, 15000000 },
50 { 15000000, 20000000 },
51 { 20000000, 25000000 },
52 { 25000000, 50000000 },
53 { 50000000, 75000000 },
54 { 75000000, 100000000 },
55 { 100000000, 125000000 },
56};
57
58enum vco_freq_range {
59 VCO_LOW = 700000000U,
60 VCO_MID = 1200000000U,
61 VCO_HIGH = 2200000000U,
62 VCO_HIGH_HIGH = 3100000000U,
63 VCO_MAX = 4000000000U,
64};
65
66struct iproc_pll;
67
68struct iproc_clk {
69 struct clk_hw hw;
70 const char *name;
71 struct iproc_pll *pll;
72 unsigned long rate;
73 const struct iproc_clk_ctrl *ctrl;
74};
75
76struct iproc_pll {
77 void __iomem *pll_base;
78 void __iomem *pwr_base;
79 void __iomem *asiu_base;
80
81 const struct iproc_pll_ctrl *ctrl;
82 const struct iproc_pll_vco_param *vco_param;
83 unsigned int num_vco_entries;
84
85 struct clk_onecell_data clk_data;
86 struct iproc_clk *clks;
87};
88
89#define to_iproc_clk(hw) container_of(hw, struct iproc_clk, hw)
90
91/*
92 * Based on the target frequency, find a match from the VCO frequency parameter
93 * table and return its index
94 */
95static int pll_get_rate_index(struct iproc_pll *pll, unsigned int target_rate)
96{
97 int i;
98
99 for (i = 0; i < pll->num_vco_entries; i++)
100 if (target_rate == pll->vco_param[i].rate)
101 break;
102
103 if (i >= pll->num_vco_entries)
104 return -EINVAL;
105
106 return i;
107}
108
109static int get_kp(unsigned long ref_freq, enum kp_band kp_index)
110{
111 int i;
112
113 if (ref_freq < ref_freq_table[0][0])
114 return -EINVAL;
115
116 for (i = 0; i < NUM_FREQ_BANDS; i++) {
117 if (ref_freq >= ref_freq_table[i][0] &&
118 ref_freq < ref_freq_table[i][1])
119 return kp_table[kp_index][i];
120 }
121 return -EINVAL;
122}
123
124static int pll_wait_for_lock(struct iproc_pll *pll)
125{
126 int i;
127 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
128
129 for (i = 0; i < LOCK_DELAY; i++) {
130 u32 val = readl(pll->pll_base + ctrl->status.offset);
131
132 if (val & (1 << ctrl->status.shift))
133 return 0;
134 udelay(10);
135 }
136
137 return -EIO;
138}
139
140static void __pll_disable(struct iproc_pll *pll)
141{
142 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
143 u32 val;
144
145 if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
146 val = readl(pll->asiu_base + ctrl->asiu.offset);
147 val &= ~(1 << ctrl->asiu.en_shift);
148 writel(val, pll->asiu_base + ctrl->asiu.offset);
149 }
150
151 /* latch input value so core power can be shut down */
152 val = readl(pll->pwr_base + ctrl->aon.offset);
153 val |= (1 << ctrl->aon.iso_shift);
154 writel(val, pll->pwr_base + ctrl->aon.offset);
155
156 /* power down the core */
157 val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
158 writel(val, pll->pwr_base + ctrl->aon.offset);
159}
160
161static int __pll_enable(struct iproc_pll *pll)
162{
163 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
164 u32 val;
165
166 /* power up the PLL and make sure it's not latched */
167 val = readl(pll->pwr_base + ctrl->aon.offset);
168 val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift;
169 val &= ~(1 << ctrl->aon.iso_shift);
170 writel(val, pll->pwr_base + ctrl->aon.offset);
171
172 /* certain PLLs also need to be ungated from the ASIU top level */
173 if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
174 val = readl(pll->asiu_base + ctrl->asiu.offset);
175 val |= (1 << ctrl->asiu.en_shift);
176 writel(val, pll->asiu_base + ctrl->asiu.offset);
177 }
178
179 return 0;
180}
181
182static void __pll_put_in_reset(struct iproc_pll *pll)
183{
184 u32 val;
185 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
186 const struct iproc_pll_reset_ctrl *reset = &ctrl->reset;
187
188 val = readl(pll->pll_base + reset->offset);
189 val &= ~(1 << reset->reset_shift | 1 << reset->p_reset_shift);
190 writel(val, pll->pll_base + reset->offset);
191 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
192 readl(pll->pll_base + reset->offset);
193}
194
195static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp,
196 unsigned int ka, unsigned int ki)
197{
198 u32 val;
199 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
200 const struct iproc_pll_reset_ctrl *reset = &ctrl->reset;
201
202 val = readl(pll->pll_base + reset->offset);
203 val &= ~(bit_mask(reset->ki_width) << reset->ki_shift |
204 bit_mask(reset->kp_width) << reset->kp_shift |
205 bit_mask(reset->ka_width) << reset->ka_shift);
206 val |= ki << reset->ki_shift | kp << reset->kp_shift |
207 ka << reset->ka_shift;
208 val |= 1 << reset->reset_shift | 1 << reset->p_reset_shift;
209 writel(val, pll->pll_base + reset->offset);
210 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
211 readl(pll->pll_base + reset->offset);
212}
213
214static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index,
215 unsigned long parent_rate)
216{
217 struct iproc_pll *pll = clk->pll;
218 const struct iproc_pll_vco_param *vco = &pll->vco_param[rate_index];
219 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
220 int ka = 0, ki, kp, ret;
221 unsigned long rate = vco->rate;
222 u32 val;
223 enum kp_band kp_index;
224 unsigned long ref_freq;
225
226 /*
227 * reference frequency = parent frequency / PDIV
228 * If PDIV = 0, then it becomes a multiplier (x2)
229 */
230 if (vco->pdiv == 0)
231 ref_freq = parent_rate * 2;
232 else
233 ref_freq = parent_rate / vco->pdiv;
234
235 /* determine Ki and Kp index based on target VCO frequency */
236 if (rate >= VCO_LOW && rate < VCO_HIGH) {
237 ki = 4;
238 kp_index = KP_BAND_MID;
239 } else if (rate >= VCO_HIGH && rate && rate < VCO_HIGH_HIGH) {
240 ki = 3;
241 kp_index = KP_BAND_HIGH;
242 } else if (rate >= VCO_HIGH_HIGH && rate < VCO_MAX) {
243 ki = 3;
244 kp_index = KP_BAND_HIGH_HIGH;
245 } else {
246 pr_err("%s: pll: %s has invalid rate: %lu\n", __func__,
247 clk->name, rate);
248 return -EINVAL;
249 }
250
251 kp = get_kp(ref_freq, kp_index);
252 if (kp < 0) {
253 pr_err("%s: pll: %s has invalid kp\n", __func__, clk->name);
254 return kp;
255 }
256
257 ret = __pll_enable(pll);
258 if (ret) {
259 pr_err("%s: pll: %s fails to enable\n", __func__, clk->name);
260 return ret;
261 }
262
263 /* put PLL in reset */
264 __pll_put_in_reset(pll);
265
266 writel(0, pll->pll_base + ctrl->vco_ctrl.u_offset);
267 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
268 readl(pll->pll_base + ctrl->vco_ctrl.u_offset);
269 val = readl(pll->pll_base + ctrl->vco_ctrl.l_offset);
270
271 if (rate >= VCO_LOW && rate < VCO_MID)
272 val |= (1 << PLL_VCO_LOW_SHIFT);
273
274 if (rate < VCO_HIGH)
275 val &= ~(1 << PLL_VCO_HIGH_SHIFT);
276 else
277 val |= (1 << PLL_VCO_HIGH_SHIFT);
278
279 writel(val, pll->pll_base + ctrl->vco_ctrl.l_offset);
280 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
281 readl(pll->pll_base + ctrl->vco_ctrl.l_offset);
282
283 /* program integer part of NDIV */
284 val = readl(pll->pll_base + ctrl->ndiv_int.offset);
285 val &= ~(bit_mask(ctrl->ndiv_int.width) << ctrl->ndiv_int.shift);
286 val |= vco->ndiv_int << ctrl->ndiv_int.shift;
287 writel(val, pll->pll_base + ctrl->ndiv_int.offset);
288 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
289 readl(pll->pll_base + ctrl->ndiv_int.offset);
290
291 /* program fractional part of NDIV */
292 if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
293 val = readl(pll->pll_base + ctrl->ndiv_frac.offset);
294 val &= ~(bit_mask(ctrl->ndiv_frac.width) <<
295 ctrl->ndiv_frac.shift);
296 val |= vco->ndiv_frac << ctrl->ndiv_frac.shift;
297 writel(val, pll->pll_base + ctrl->ndiv_frac.offset);
298 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
299 readl(pll->pll_base + ctrl->ndiv_frac.offset);
300 }
301
302 /* program PDIV */
303 val = readl(pll->pll_base + ctrl->pdiv.offset);
304 val &= ~(bit_mask(ctrl->pdiv.width) << ctrl->pdiv.shift);
305 val |= vco->pdiv << ctrl->pdiv.shift;
306 writel(val, pll->pll_base + ctrl->pdiv.offset);
307 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
308 readl(pll->pll_base + ctrl->pdiv.offset);
309
310 __pll_bring_out_reset(pll, kp, ka, ki);
311
312 ret = pll_wait_for_lock(pll);
313 if (ret < 0) {
314 pr_err("%s: pll: %s failed to lock\n", __func__, clk->name);
315 return ret;
316 }
317
318 return 0;
319}
320
321static int iproc_pll_enable(struct clk_hw *hw)
322{
323 struct iproc_clk *clk = to_iproc_clk(hw);
324 struct iproc_pll *pll = clk->pll;
325
326 return __pll_enable(pll);
327}
328
329static void iproc_pll_disable(struct clk_hw *hw)
330{
331 struct iproc_clk *clk = to_iproc_clk(hw);
332 struct iproc_pll *pll = clk->pll;
333 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
334
335 if (ctrl->flags & IPROC_CLK_AON)
336 return;
337
338 __pll_disable(pll);
339}
340
341static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw,
342 unsigned long parent_rate)
343{
344 struct iproc_clk *clk = to_iproc_clk(hw);
345 struct iproc_pll *pll = clk->pll;
346 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
347 u32 val;
348 u64 ndiv;
349 unsigned int ndiv_int, ndiv_frac, pdiv;
350
351 if (parent_rate == 0)
352 return 0;
353
354 /* PLL needs to be locked */
355 val = readl(pll->pll_base + ctrl->status.offset);
356 if ((val & (1 << ctrl->status.shift)) == 0) {
357 clk->rate = 0;
358 return 0;
359 }
360
361 /*
362 * PLL output frequency =
363 *
364 * ((ndiv_int + ndiv_frac / 2^20) * (parent clock rate / pdiv)
365 */
366 val = readl(pll->pll_base + ctrl->ndiv_int.offset);
367 ndiv_int = (val >> ctrl->ndiv_int.shift) &
368 bit_mask(ctrl->ndiv_int.width);
369 ndiv = ndiv_int << ctrl->ndiv_int.shift;
370
371 if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
372 val = readl(pll->pll_base + ctrl->ndiv_frac.offset);
373 ndiv_frac = (val >> ctrl->ndiv_frac.shift) &
374 bit_mask(ctrl->ndiv_frac.width);
375
376 if (ndiv_frac != 0)
377 ndiv = (ndiv_int << ctrl->ndiv_int.shift) | ndiv_frac;
378 }
379
380 val = readl(pll->pll_base + ctrl->pdiv.offset);
381 pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width);
382
383 clk->rate = (ndiv * parent_rate) >> ctrl->ndiv_int.shift;
384
385 if (pdiv == 0)
386 clk->rate *= 2;
387 else
388 clk->rate /= pdiv;
389
390 return clk->rate;
391}
392
393static long iproc_pll_round_rate(struct clk_hw *hw, unsigned long rate,
394 unsigned long *parent_rate)
395{
396 unsigned i;
397 struct iproc_clk *clk = to_iproc_clk(hw);
398 struct iproc_pll *pll = clk->pll;
399
400 if (rate == 0 || *parent_rate == 0 || !pll->vco_param)
401 return -EINVAL;
402
403 for (i = 0; i < pll->num_vco_entries; i++) {
404 if (rate <= pll->vco_param[i].rate)
405 break;
406 }
407
408 if (i == pll->num_vco_entries)
409 i--;
410
411 return pll->vco_param[i].rate;
412}
413
414static int iproc_pll_set_rate(struct clk_hw *hw, unsigned long rate,
415 unsigned long parent_rate)
416{
417 struct iproc_clk *clk = to_iproc_clk(hw);
418 struct iproc_pll *pll = clk->pll;
419 int rate_index, ret;
420
421 rate_index = pll_get_rate_index(pll, rate);
422 if (rate_index < 0)
423 return rate_index;
424
425 ret = pll_set_rate(clk, rate_index, parent_rate);
426 return ret;
427}
428
429static const struct clk_ops iproc_pll_ops = {
430 .enable = iproc_pll_enable,
431 .disable = iproc_pll_disable,
432 .recalc_rate = iproc_pll_recalc_rate,
433 .round_rate = iproc_pll_round_rate,
434 .set_rate = iproc_pll_set_rate,
435};
436
437static int iproc_clk_enable(struct clk_hw *hw)
438{
439 struct iproc_clk *clk = to_iproc_clk(hw);
440 const struct iproc_clk_ctrl *ctrl = clk->ctrl;
441 struct iproc_pll *pll = clk->pll;
442 u32 val;
443
444 /* channel enable is active low */
445 val = readl(pll->pll_base + ctrl->enable.offset);
446 val &= ~(1 << ctrl->enable.enable_shift);
447 writel(val, pll->pll_base + ctrl->enable.offset);
448
449 /* also make sure channel is not held */
450 val = readl(pll->pll_base + ctrl->enable.offset);
451 val &= ~(1 << ctrl->enable.hold_shift);
452 writel(val, pll->pll_base + ctrl->enable.offset);
453 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
454 readl(pll->pll_base + ctrl->enable.offset);
455
456 return 0;
457}
458
459static void iproc_clk_disable(struct clk_hw *hw)
460{
461 struct iproc_clk *clk = to_iproc_clk(hw);
462 const struct iproc_clk_ctrl *ctrl = clk->ctrl;
463 struct iproc_pll *pll = clk->pll;
464 u32 val;
465
466 if (ctrl->flags & IPROC_CLK_AON)
467 return;
468
469 val = readl(pll->pll_base + ctrl->enable.offset);
470 val |= 1 << ctrl->enable.enable_shift;
471 writel(val, pll->pll_base + ctrl->enable.offset);
472 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
473 readl(pll->pll_base + ctrl->enable.offset);
474}
475
476static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw,
477 unsigned long parent_rate)
478{
479 struct iproc_clk *clk = to_iproc_clk(hw);
480 const struct iproc_clk_ctrl *ctrl = clk->ctrl;
481 struct iproc_pll *pll = clk->pll;
482 u32 val;
483 unsigned int mdiv;
484
485 if (parent_rate == 0)
486 return 0;
487
488 val = readl(pll->pll_base + ctrl->mdiv.offset);
489 mdiv = (val >> ctrl->mdiv.shift) & bit_mask(ctrl->mdiv.width);
490 if (mdiv == 0)
491 mdiv = 256;
492
493 clk->rate = parent_rate / mdiv;
494
495 return clk->rate;
496}
497
498static long iproc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
499 unsigned long *parent_rate)
500{
501 unsigned int div;
502
503 if (rate == 0 || *parent_rate == 0)
504 return -EINVAL;
505
506 if (rate == *parent_rate)
507 return *parent_rate;
508
509 div = DIV_ROUND_UP(*parent_rate, rate);
510 if (div < 2)
511 return *parent_rate;
512
513 if (div > 256)
514 div = 256;
515
516 return *parent_rate / div;
517}
518
519static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
520 unsigned long parent_rate)
521{
522 struct iproc_clk *clk = to_iproc_clk(hw);
523 const struct iproc_clk_ctrl *ctrl = clk->ctrl;
524 struct iproc_pll *pll = clk->pll;
525 u32 val;
526 unsigned int div;
527
528 if (rate == 0 || parent_rate == 0)
529 return -EINVAL;
530
531 div = DIV_ROUND_UP(parent_rate, rate);
532 if (div > 256)
533 return -EINVAL;
534
535 val = readl(pll->pll_base + ctrl->mdiv.offset);
536 if (div == 256) {
537 val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift);
538 } else {
539 val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift);
540 val |= div << ctrl->mdiv.shift;
541 }
542 writel(val, pll->pll_base + ctrl->mdiv.offset);
543 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
544 readl(pll->pll_base + ctrl->mdiv.offset);
545 clk->rate = parent_rate / div;
546
547 return 0;
548}
549
550static const struct clk_ops iproc_clk_ops = {
551 .enable = iproc_clk_enable,
552 .disable = iproc_clk_disable,
553 .recalc_rate = iproc_clk_recalc_rate,
554 .round_rate = iproc_clk_round_rate,
555 .set_rate = iproc_clk_set_rate,
556};
557
558/**
559 * Some PLLs require the PLL SW override bit to be set before changes can be
560 * applied to the PLL
561 */
562static void iproc_pll_sw_cfg(struct iproc_pll *pll)
563{
564 const struct iproc_pll_ctrl *ctrl = pll->ctrl;
565
566 if (ctrl->flags & IPROC_CLK_PLL_NEEDS_SW_CFG) {
567 u32 val;
568
569 val = readl(pll->pll_base + ctrl->sw_ctrl.offset);
570 val |= BIT(ctrl->sw_ctrl.shift);
571 writel(val, pll->pll_base + ctrl->sw_ctrl.offset);
572 if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
573 readl(pll->pll_base + ctrl->sw_ctrl.offset);
574 }
575}
576
577void __init iproc_pll_clk_setup(struct device_node *node,
578 const struct iproc_pll_ctrl *pll_ctrl,
579 const struct iproc_pll_vco_param *vco,
580 unsigned int num_vco_entries,
581 const struct iproc_clk_ctrl *clk_ctrl,
582 unsigned int num_clks)
583{
584 int i, ret;
585 struct clk *clk;
586 struct iproc_pll *pll;
587 struct iproc_clk *iclk;
588 struct clk_init_data init;
589 const char *parent_name;
590
591 if (WARN_ON(!pll_ctrl) || WARN_ON(!clk_ctrl))
592 return;
593
594 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
595 if (WARN_ON(!pll))
596 return;
597
598 pll->clk_data.clk_num = num_clks;
599 pll->clk_data.clks = kcalloc(num_clks, sizeof(*pll->clk_data.clks),
600 GFP_KERNEL);
601 if (WARN_ON(!pll->clk_data.clks))
602 goto err_clk_data;
603
604 pll->clks = kcalloc(num_clks, sizeof(*pll->clks), GFP_KERNEL);
605 if (WARN_ON(!pll->clks))
606 goto err_clks;
607
608 pll->pll_base = of_iomap(node, 0);
609 if (WARN_ON(!pll->pll_base))
610 goto err_pll_iomap;
611
612 pll->pwr_base = of_iomap(node, 1);
613 if (WARN_ON(!pll->pwr_base))
614 goto err_pwr_iomap;
615
616 /* some PLLs require gating control at the top ASIU level */
617 if (pll_ctrl->flags & IPROC_CLK_PLL_ASIU) {
618 pll->asiu_base = of_iomap(node, 2);
619 if (WARN_ON(!pll->asiu_base))
620 goto err_asiu_iomap;
621 }
622
623 /* initialize and register the PLL itself */
624 pll->ctrl = pll_ctrl;
625
626 iclk = &pll->clks[0];
627 iclk->pll = pll;
628 iclk->name = node->name;
629
630 init.name = node->name;
631 init.ops = &iproc_pll_ops;
632 init.flags = 0;
633 parent_name = of_clk_get_parent_name(node, 0);
634 init.parent_names = (parent_name ? &parent_name : NULL);
635 init.num_parents = (parent_name ? 1 : 0);
636 iclk->hw.init = &init;
637
638 if (vco) {
639 pll->num_vco_entries = num_vco_entries;
640 pll->vco_param = vco;
641 }
642
643 iproc_pll_sw_cfg(pll);
644
645 clk = clk_register(NULL, &iclk->hw);
646 if (WARN_ON(IS_ERR(clk)))
647 goto err_pll_register;
648
649 pll->clk_data.clks[0] = clk;
650
651 /* now initialize and register all leaf clocks */
652 for (i = 1; i < num_clks; i++) {
653 const char *clk_name;
654
655 memset(&init, 0, sizeof(init));
656 parent_name = node->name;
657
658 clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL);
659 if (WARN_ON(!clk_name))
660 goto err_clk_register;
661
662 ret = of_property_read_string_index(node, "clock-output-names",
663 i, &clk_name);
664 if (WARN_ON(ret))
665 goto err_clk_register;
666
667 iclk = &pll->clks[i];
668 iclk->name = clk_name;
669 iclk->pll = pll;
670 iclk->ctrl = &clk_ctrl[i];
671
672 init.name = clk_name;
673 init.ops = &iproc_clk_ops;
674 init.flags = 0;
675 init.parent_names = (parent_name ? &parent_name : NULL);
676 init.num_parents = (parent_name ? 1 : 0);
677 iclk->hw.init = &init;
678
679 clk = clk_register(NULL, &iclk->hw);
680 if (WARN_ON(IS_ERR(clk)))
681 goto err_clk_register;
682
683 pll->clk_data.clks[i] = clk;
684 }
685
686 ret = of_clk_add_provider(node, of_clk_src_onecell_get, &pll->clk_data);
687 if (WARN_ON(ret))
688 goto err_clk_register;
689
690 return;
691
692err_clk_register:
693 for (i = 0; i < num_clks; i++) {
694 kfree(pll->clks[i].name);
695 clk_unregister(pll->clk_data.clks[i]);
696 }
697
698err_pll_register:
699 if (pll->asiu_base)
700 iounmap(pll->asiu_base);
701
702err_asiu_iomap:
703 iounmap(pll->pwr_base);
704
705err_pwr_iomap:
706 iounmap(pll->pll_base);
707
708err_pll_iomap:
709 kfree(pll->clks);
710
711err_clks:
712 kfree(pll->clk_data.clks);
713
714err_clk_data:
715 kfree(pll);
716}
diff --git a/drivers/clk/bcm/clk-iproc.h b/drivers/clk/bcm/clk-iproc.h
new file mode 100644
index 000000000000..d834b7abd5c6
--- /dev/null
+++ b/drivers/clk/bcm/clk-iproc.h
@@ -0,0 +1,178 @@
1/*
2 * Copyright (C) 2014 Broadcom Corporation
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#ifndef _CLK_IPROC_H
15#define _CLK_IPROC_H
16
17#include <linux/kernel.h>
18#include <linux/list.h>
19#include <linux/spinlock.h>
20#include <linux/slab.h>
21#include <linux/device.h>
22#include <linux/of.h>
23#include <linux/clk-provider.h>
24
25#define IPROC_CLK_NAME_LEN 25
26#define IPROC_CLK_INVALID_OFFSET 0xffffffff
27#define bit_mask(width) ((1 << (width)) - 1)
28
29/* clocks that should not be disabled at runtime */
30#define IPROC_CLK_AON BIT(0)
31
32/* PLL that requires gating through ASIU */
33#define IPROC_CLK_PLL_ASIU BIT(1)
34
35/* PLL that has fractional part of the NDIV */
36#define IPROC_CLK_PLL_HAS_NDIV_FRAC BIT(2)
37
38/*
39 * Some of the iProc PLL/clocks may have an ASIC bug that requires read back
40 * of the same register following the write to flush the write transaction into
41 * the intended register
42 */
43#define IPROC_CLK_NEEDS_READ_BACK BIT(3)
44
45/*
46 * Some PLLs require the PLL SW override bit to be set before changes can be
47 * applied to the PLL
48 */
49#define IPROC_CLK_PLL_NEEDS_SW_CFG BIT(4)
50
51/*
52 * Parameters for VCO frequency configuration
53 *
54 * VCO frequency =
55 * ((ndiv_int + ndiv_frac / 2^20) * (ref freqeuncy / pdiv)
56 */
57struct iproc_pll_vco_param {
58 unsigned long rate;
59 unsigned int ndiv_int;
60 unsigned int ndiv_frac;
61 unsigned int pdiv;
62};
63
64struct iproc_clk_reg_op {
65 unsigned int offset;
66 unsigned int shift;
67 unsigned int width;
68};
69
70/*
71 * Clock gating control at the top ASIU level
72 */
73struct iproc_asiu_gate {
74 unsigned int offset;
75 unsigned int en_shift;
76};
77
78/*
79 * Control of powering on/off of a PLL
80 *
81 * Before powering off a PLL, input isolation (ISO) needs to be enabled
82 */
83struct iproc_pll_aon_pwr_ctrl {
84 unsigned int offset;
85 unsigned int pwr_width;
86 unsigned int pwr_shift;
87 unsigned int iso_shift;
88};
89
90/*
91 * Control of the PLL reset, with Ki, Kp, and Ka parameters
92 */
93struct iproc_pll_reset_ctrl {
94 unsigned int offset;
95 unsigned int reset_shift;
96 unsigned int p_reset_shift;
97 unsigned int ki_shift;
98 unsigned int ki_width;
99 unsigned int kp_shift;
100 unsigned int kp_width;
101 unsigned int ka_shift;
102 unsigned int ka_width;
103};
104
105/*
106 * To enable SW control of the PLL
107 */
108struct iproc_pll_sw_ctrl {
109 unsigned int offset;
110 unsigned int shift;
111};
112
113struct iproc_pll_vco_ctrl {
114 unsigned int u_offset;
115 unsigned int l_offset;
116};
117
118/*
119 * Main PLL control parameters
120 */
121struct iproc_pll_ctrl {
122 unsigned long flags;
123 struct iproc_pll_aon_pwr_ctrl aon;
124 struct iproc_asiu_gate asiu;
125 struct iproc_pll_reset_ctrl reset;
126 struct iproc_pll_sw_ctrl sw_ctrl;
127 struct iproc_clk_reg_op ndiv_int;
128 struct iproc_clk_reg_op ndiv_frac;
129 struct iproc_clk_reg_op pdiv;
130 struct iproc_pll_vco_ctrl vco_ctrl;
131 struct iproc_clk_reg_op status;
132};
133
134/*
135 * Controls enabling/disabling a PLL derived clock
136 */
137struct iproc_clk_enable_ctrl {
138 unsigned int offset;
139 unsigned int enable_shift;
140 unsigned int hold_shift;
141 unsigned int bypass_shift;
142};
143
144/*
145 * Main clock control parameters for clocks derived from the PLLs
146 */
147struct iproc_clk_ctrl {
148 unsigned int channel;
149 unsigned long flags;
150 struct iproc_clk_enable_ctrl enable;
151 struct iproc_clk_reg_op mdiv;
152};
153
154/*
155 * Divisor of the ASIU clocks
156 */
157struct iproc_asiu_div {
158 unsigned int offset;
159 unsigned int en_shift;
160 unsigned int high_shift;
161 unsigned int high_width;
162 unsigned int low_shift;
163 unsigned int low_width;
164};
165
166void __init iproc_armpll_setup(struct device_node *node);
167void __init iproc_pll_clk_setup(struct device_node *node,
168 const struct iproc_pll_ctrl *pll_ctrl,
169 const struct iproc_pll_vco_param *vco,
170 unsigned int num_vco_entries,
171 const struct iproc_clk_ctrl *clk_ctrl,
172 unsigned int num_clks);
173void __init iproc_asiu_setup(struct device_node *node,
174 const struct iproc_asiu_div *div,
175 const struct iproc_asiu_gate *gate,
176 unsigned int num_clks);
177
178#endif /* _CLK_IPROC_H */