1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (C) 2014 Broadcom Corporation
3
4#include <linux/kernel.h>
5#include <linux/err.h>
6#include <linux/clk-provider.h>
7#include <linux/io.h>
8#include <linux/of.h>
9#include <linux/clkdev.h>
10#include <linux/of_address.h>
11#include <linux/delay.h>
12
13#include <dt-bindings/clock/bcm-cygnus.h>
14#include "clk-iproc.h"
15
16#define REG_VAL(o, s, w) { .offset = o, .shift = s, .width = w, }
17
18#define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \
19	.pwr_shift = ps, .iso_shift = is }
20
21#define SW_CTRL_VAL(o, s) { .offset = o, .shift = s, }
22
23#define ASIU_DIV_VAL(o, es, hs, hw, ls, lw) \
24		{ .offset = o, .en_shift = es, .high_shift = hs, \
25		.high_width = hw, .low_shift = ls, .low_width = lw }
26
27#define RESET_VAL(o, rs, prs) { .offset = o, .reset_shift = rs, \
28	.p_reset_shift = prs }
29
30#define DF_VAL(o, kis, kiw, kps, kpw, kas, kaw) { .offset = o, .ki_shift = kis,\
31	.ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas,    \
32	.ka_width = kaw }
33
34#define VCO_CTRL_VAL(uo, lo) { .u_offset = uo, .l_offset = lo }
35
36#define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \
37	.hold_shift = hs, .bypass_shift = bs }
38
39#define ASIU_GATE_VAL(o, es) { .offset = o, .en_shift = es }
40
41static void __init cygnus_armpll_init(struct device_node *node)
42{
43	iproc_armpll_setup(node);
44}
45CLK_OF_DECLARE(cygnus_armpll, "brcm,cygnus-armpll", cygnus_armpll_init);
46
47static const struct iproc_pll_ctrl genpll = {
48	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
49		IPROC_CLK_PLL_NEEDS_SW_CFG,
50	.aon = AON_VAL(0x0, 2, 1, 0),
51	.reset = RESET_VAL(0x0, 11, 10),
52	.dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
53	.sw_ctrl = SW_CTRL_VAL(0x10, 31),
54	.ndiv_int = REG_VAL(0x10, 20, 10),
55	.ndiv_frac = REG_VAL(0x10, 0, 20),
56	.pdiv = REG_VAL(0x14, 0, 4),
57	.vco_ctrl = VCO_CTRL_VAL(0x18, 0x1c),
58	.status = REG_VAL(0x28, 12, 1),
59};
60
61static const struct iproc_clk_ctrl genpll_clk[] = {
62	[BCM_CYGNUS_GENPLL_AXI21_CLK] = {
63		.channel = BCM_CYGNUS_GENPLL_AXI21_CLK,
64		.flags = IPROC_CLK_AON,
65		.enable = ENABLE_VAL(0x4, 6, 0, 12),
66		.mdiv = REG_VAL(0x20, 0, 8),
67	},
68	[BCM_CYGNUS_GENPLL_250MHZ_CLK] = {
69		.channel = BCM_CYGNUS_GENPLL_250MHZ_CLK,
70		.flags = IPROC_CLK_AON,
71		.enable = ENABLE_VAL(0x4, 7, 1, 13),
72		.mdiv = REG_VAL(0x20, 10, 8),
73	},
74	[BCM_CYGNUS_GENPLL_IHOST_SYS_CLK] = {
75		.channel = BCM_CYGNUS_GENPLL_IHOST_SYS_CLK,
76		.flags = IPROC_CLK_AON,
77		.enable = ENABLE_VAL(0x4, 8, 2, 14),
78		.mdiv = REG_VAL(0x20, 20, 8),
79	},
80	[BCM_CYGNUS_GENPLL_ENET_SW_CLK] = {
81		.channel = BCM_CYGNUS_GENPLL_ENET_SW_CLK,
82		.flags = IPROC_CLK_AON,
83		.enable = ENABLE_VAL(0x4, 9, 3, 15),
84		.mdiv = REG_VAL(0x24, 0, 8),
85	},
86	[BCM_CYGNUS_GENPLL_AUDIO_125_CLK] = {
87		.channel = BCM_CYGNUS_GENPLL_AUDIO_125_CLK,
88		.flags = IPROC_CLK_AON,
89		.enable = ENABLE_VAL(0x4, 10, 4, 16),
90		.mdiv = REG_VAL(0x24, 10, 8),
91	},
92	[BCM_CYGNUS_GENPLL_CAN_CLK] = {
93		.channel = BCM_CYGNUS_GENPLL_CAN_CLK,
94		.flags = IPROC_CLK_AON,
95		.enable = ENABLE_VAL(0x4, 11, 5, 17),
96		.mdiv = REG_VAL(0x24, 20, 8),
97	},
98};
99
100static void __init cygnus_genpll_clk_init(struct device_node *node)
101{
102	iproc_pll_clk_setup(node, &genpll, NULL, 0, genpll_clk,
103			    ARRAY_SIZE(genpll_clk));
104}
105CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll", cygnus_genpll_clk_init);
106
107static const struct iproc_pll_ctrl lcpll0 = {
108	.flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG,
109	.aon = AON_VAL(0x0, 2, 5, 4),
110	.reset = RESET_VAL(0x0, 31, 30),
111	.dig_filter = DF_VAL(0x0, 27, 3, 23, 4, 19, 4),
112	.sw_ctrl = SW_CTRL_VAL(0x4, 31),
113	.ndiv_int = REG_VAL(0x4, 16, 10),
114	.pdiv = REG_VAL(0x4, 26, 4),
115	.vco_ctrl = VCO_CTRL_VAL(0x10, 0x14),
116	.status = REG_VAL(0x18, 12, 1),
117};
118
119static const struct iproc_clk_ctrl lcpll0_clk[] = {
120	[BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK] = {
121		.channel = BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK,
122		.flags = IPROC_CLK_AON,
123		.enable = ENABLE_VAL(0x0, 7, 1, 13),
124		.mdiv = REG_VAL(0x8, 0, 8),
125	},
126	[BCM_CYGNUS_LCPLL0_DDR_PHY_CLK] = {
127		.channel = BCM_CYGNUS_LCPLL0_DDR_PHY_CLK,
128		.flags = IPROC_CLK_AON,
129		.enable = ENABLE_VAL(0x0, 8, 2, 14),
130		.mdiv = REG_VAL(0x8, 10, 8),
131	},
132	[BCM_CYGNUS_LCPLL0_SDIO_CLK] = {
133		.channel = BCM_CYGNUS_LCPLL0_SDIO_CLK,
134		.flags = IPROC_CLK_AON,
135		.enable = ENABLE_VAL(0x0, 9, 3, 15),
136		.mdiv = REG_VAL(0x8, 20, 8),
137	},
138	[BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK] = {
139		.channel = BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK,
140		.flags = IPROC_CLK_AON,
141		.enable = ENABLE_VAL(0x0, 10, 4, 16),
142		.mdiv = REG_VAL(0xc, 0, 8),
143	},
144	[BCM_CYGNUS_LCPLL0_SMART_CARD_CLK] = {
145		.channel = BCM_CYGNUS_LCPLL0_SMART_CARD_CLK,
146		.flags = IPROC_CLK_AON,
147		.enable = ENABLE_VAL(0x0, 11, 5, 17),
148		.mdiv = REG_VAL(0xc, 10, 8),
149	},
150	[BCM_CYGNUS_LCPLL0_CH5_UNUSED] = {
151		.channel = BCM_CYGNUS_LCPLL0_CH5_UNUSED,
152		.flags = IPROC_CLK_AON,
153		.enable = ENABLE_VAL(0x0, 12, 6, 18),
154		.mdiv = REG_VAL(0xc, 20, 8),
155	},
156};
157
158static void __init cygnus_lcpll0_clk_init(struct device_node *node)
159{
160	iproc_pll_clk_setup(node, &lcpll0, NULL, 0, lcpll0_clk,
161			    ARRAY_SIZE(lcpll0_clk));
162}
163CLK_OF_DECLARE(cygnus_lcpll0, "brcm,cygnus-lcpll0", cygnus_lcpll0_clk_init);
164
165/*
166 * MIPI PLL VCO frequency parameter table
167 */
168static const struct iproc_pll_vco_param mipipll_vco_params[] = {
169	/* rate (Hz) ndiv_int ndiv_frac pdiv */
170	{ 750000000UL,   30,     0,        1 },
171	{ 1000000000UL,  40,     0,        1 },
172	{ 1350000000ul,  54,     0,        1 },
173	{ 2000000000UL,  80,     0,        1 },
174	{ 2100000000UL,  84,     0,        1 },
175	{ 2250000000UL,  90,     0,        1 },
176	{ 2500000000UL,  100,    0,        1 },
177	{ 2700000000UL,  54,     0,        0 },
178	{ 2975000000UL,  119,    0,        1 },
179	{ 3100000000UL,  124,    0,        1 },
180	{ 3150000000UL,  126,    0,        1 },
181};
182
183static const struct iproc_pll_ctrl mipipll = {
184	.flags = IPROC_CLK_PLL_ASIU | IPROC_CLK_PLL_HAS_NDIV_FRAC |
185		 IPROC_CLK_NEEDS_READ_BACK,
186	.aon = AON_VAL(0x0, 4, 17, 16),
187	.asiu = ASIU_GATE_VAL(0x0, 3),
188	.reset = RESET_VAL(0x0, 11, 10),
189	.dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 4),
190	.ndiv_int = REG_VAL(0x10, 20, 10),
191	.ndiv_frac = REG_VAL(0x10, 0, 20),
192	.pdiv = REG_VAL(0x14, 0, 4),
193	.vco_ctrl = VCO_CTRL_VAL(0x18, 0x1c),
194	.status = REG_VAL(0x28, 12, 1),
195};
196
197static const struct iproc_clk_ctrl mipipll_clk[] = {
198	[BCM_CYGNUS_MIPIPLL_CH0_UNUSED] = {
199		.channel = BCM_CYGNUS_MIPIPLL_CH0_UNUSED,
200		.flags = IPROC_CLK_NEEDS_READ_BACK,
201		.enable = ENABLE_VAL(0x4, 12, 6, 18),
202		.mdiv = REG_VAL(0x20, 0, 8),
203	},
204	[BCM_CYGNUS_MIPIPLL_CH1_LCD] = {
205		.channel = BCM_CYGNUS_MIPIPLL_CH1_LCD,
206		.flags = IPROC_CLK_NEEDS_READ_BACK,
207		.enable = ENABLE_VAL(0x4, 13, 7, 19),
208		.mdiv = REG_VAL(0x20, 10, 8),
209	},
210	[BCM_CYGNUS_MIPIPLL_CH2_V3D] = {
211		.channel = BCM_CYGNUS_MIPIPLL_CH2_V3D,
212		.flags = IPROC_CLK_NEEDS_READ_BACK,
213		.enable = ENABLE_VAL(0x4, 14, 8, 20),
214		.mdiv = REG_VAL(0x20, 20, 8),
215	},
216	[BCM_CYGNUS_MIPIPLL_CH3_UNUSED] = {
217		.channel = BCM_CYGNUS_MIPIPLL_CH3_UNUSED,
218		.flags = IPROC_CLK_NEEDS_READ_BACK,
219		.enable = ENABLE_VAL(0x4, 15, 9, 21),
220		.mdiv = REG_VAL(0x24, 0, 8),
221	},
222	[BCM_CYGNUS_MIPIPLL_CH4_UNUSED] = {
223		.channel = BCM_CYGNUS_MIPIPLL_CH4_UNUSED,
224		.flags = IPROC_CLK_NEEDS_READ_BACK,
225		.enable = ENABLE_VAL(0x4, 16, 10, 22),
226		.mdiv = REG_VAL(0x24, 10, 8),
227	},
228	[BCM_CYGNUS_MIPIPLL_CH5_UNUSED] = {
229		.channel = BCM_CYGNUS_MIPIPLL_CH5_UNUSED,
230		.flags = IPROC_CLK_NEEDS_READ_BACK,
231		.enable = ENABLE_VAL(0x4, 17, 11, 23),
232		.mdiv = REG_VAL(0x24, 20, 8),
233	},
234};
235
236static void __init cygnus_mipipll_clk_init(struct device_node *node)
237{
238	iproc_pll_clk_setup(node, &mipipll, mipipll_vco_params,
239			    ARRAY_SIZE(mipipll_vco_params), mipipll_clk,
240			    ARRAY_SIZE(mipipll_clk));
241}
242CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll", cygnus_mipipll_clk_init);
243
244static const struct iproc_asiu_div asiu_div[] = {
245	[BCM_CYGNUS_ASIU_KEYPAD_CLK] = ASIU_DIV_VAL(0x0, 31, 16, 10, 0, 10),
246	[BCM_CYGNUS_ASIU_ADC_CLK] = ASIU_DIV_VAL(0x4, 31, 16, 10, 0, 10),
247	[BCM_CYGNUS_ASIU_PWM_CLK] = ASIU_DIV_VAL(0x8, 31, 16, 10, 0, 10),
248};
249
250static const struct iproc_asiu_gate asiu_gate[] = {
251	[BCM_CYGNUS_ASIU_KEYPAD_CLK] = ASIU_GATE_VAL(0x0, 7),
252	[BCM_CYGNUS_ASIU_ADC_CLK] = ASIU_GATE_VAL(0x0, 9),
253	[BCM_CYGNUS_ASIU_PWM_CLK] = ASIU_GATE_VAL(IPROC_CLK_INVALID_OFFSET, 0),
254};
255
256static void __init cygnus_asiu_init(struct device_node *node)
257{
258	iproc_asiu_setup(node, asiu_div, asiu_gate, ARRAY_SIZE(asiu_div));
259}
260CLK_OF_DECLARE(cygnus_asiu_clk, "brcm,cygnus-asiu-clk", cygnus_asiu_init);
261
262static const struct iproc_pll_ctrl audiopll = {
263	.flags = IPROC_CLK_PLL_NEEDS_SW_CFG | IPROC_CLK_PLL_HAS_NDIV_FRAC |
264		IPROC_CLK_PLL_USER_MODE_ON | IPROC_CLK_PLL_RESET_ACTIVE_LOW |
265		IPROC_CLK_PLL_CALC_PARAM,
266	.reset = RESET_VAL(0x5c, 0, 1),
267	.dig_filter = DF_VAL(0x48, 0, 3, 6, 4, 3, 3),
268	.sw_ctrl = SW_CTRL_VAL(0x4, 0),
269	.ndiv_int = REG_VAL(0x8, 0, 10),
270	.ndiv_frac = REG_VAL(0x8, 10, 20),
271	.pdiv = REG_VAL(0x44, 0, 4),
272	.vco_ctrl = VCO_CTRL_VAL(0x0c, 0x10),
273	.status = REG_VAL(0x54, 0, 1),
274	.macro_mode = REG_VAL(0x0, 0, 3),
275};
276
277static const struct iproc_clk_ctrl audiopll_clk[] = {
278	[BCM_CYGNUS_AUDIOPLL_CH0] = {
279		.channel = BCM_CYGNUS_AUDIOPLL_CH0,
280		.flags = IPROC_CLK_AON | IPROC_CLK_MCLK_DIV_BY_2,
281		.enable = ENABLE_VAL(0x14, 8, 10, 9),
282		.mdiv = REG_VAL(0x14, 0, 8),
283	},
284	[BCM_CYGNUS_AUDIOPLL_CH1] = {
285		.channel = BCM_CYGNUS_AUDIOPLL_CH1,
286		.flags = IPROC_CLK_AON,
287		.enable = ENABLE_VAL(0x18, 8, 10, 9),
288		.mdiv = REG_VAL(0x18, 0, 8),
289	},
290	[BCM_CYGNUS_AUDIOPLL_CH2] = {
291		.channel = BCM_CYGNUS_AUDIOPLL_CH2,
292		.flags = IPROC_CLK_AON,
293		.enable = ENABLE_VAL(0x1c, 8, 10, 9),
294		.mdiv = REG_VAL(0x1c, 0, 8),
295	},
296};
297
298static void __init cygnus_audiopll_clk_init(struct device_node *node)
299{
300	iproc_pll_clk_setup(node, &audiopll, NULL, 0,
301			    audiopll_clk,  ARRAY_SIZE(audiopll_clk));
302}
303CLK_OF_DECLARE(cygnus_audiopll, "brcm,cygnus-audiopll",
304			cygnus_audiopll_clk_init);
305