xref: /linux/drivers/clk/tenstorrent/atlantis-prcm.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*23c8ebc9SAnirudh Srinivasan // SPDX-License-Identifier: GPL-2.0-only
2*23c8ebc9SAnirudh Srinivasan /*
3*23c8ebc9SAnirudh Srinivasan  * Tenstorrent Atlantis PRCM Clock Driver
4*23c8ebc9SAnirudh Srinivasan  *
5*23c8ebc9SAnirudh Srinivasan  * Copyright (c) 2026 Tenstorrent
6*23c8ebc9SAnirudh Srinivasan  */
7*23c8ebc9SAnirudh Srinivasan 
8*23c8ebc9SAnirudh Srinivasan #include <dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h>
9*23c8ebc9SAnirudh Srinivasan #include <linux/auxiliary_bus.h>
10*23c8ebc9SAnirudh Srinivasan #include <linux/bitfield.h>
11*23c8ebc9SAnirudh Srinivasan #include <linux/clk-provider.h>
12*23c8ebc9SAnirudh Srinivasan #include <linux/platform_device.h>
13*23c8ebc9SAnirudh Srinivasan #include <linux/regmap.h>
14*23c8ebc9SAnirudh Srinivasan #include <linux/slab.h>
15*23c8ebc9SAnirudh Srinivasan 
16*23c8ebc9SAnirudh Srinivasan /* RCPU Clock Register Offsets */
17*23c8ebc9SAnirudh Srinivasan #define PLL_RCPU_CFG_REG	0x0000
18*23c8ebc9SAnirudh Srinivasan #define PLL_NOCC_CFG_REG	0x0004
19*23c8ebc9SAnirudh Srinivasan #define NOCC_CLK_CFG_REG	0x0008
20*23c8ebc9SAnirudh Srinivasan #define RCPU_DIV_CFG_REG	0x000C
21*23c8ebc9SAnirudh Srinivasan #define RCPU_BLK_CG_REG		0x0014
22*23c8ebc9SAnirudh Srinivasan #define LSIO_BLK_CG_REG		0x0018
23*23c8ebc9SAnirudh Srinivasan #define PLL_RCPU_EN_REG		0x011C
24*23c8ebc9SAnirudh Srinivasan #define PLL_NOCC_EN_REG		0x0120
25*23c8ebc9SAnirudh Srinivasan #define BUS_CG_REG		0x01FC
26*23c8ebc9SAnirudh Srinivasan 
27*23c8ebc9SAnirudh Srinivasan /* PLL Bit Definitions */
28*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_EN_BIT		BIT(0)
29*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_BYPASS_BIT	BIT(1)
30*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_REFDIV_MASK	GENMASK(7, 2)
31*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_REFDIV_SHIFT	2
32*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_POSTDIV1_MASK	GENMASK(10, 8)
33*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_POSTDIV1_SHIFT	8
34*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_POSTDIV2_MASK	GENMASK(13, 11)
35*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_POSTDIV2_SHIFT	11
36*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_FBDIV_MASK	GENMASK(25, 14)
37*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_FBDIV_SHIFT	14
38*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_LKDT_BIT	BIT(30)
39*23c8ebc9SAnirudh Srinivasan #define PLL_CFG_LOCK_BIT	BIT(31)
40*23c8ebc9SAnirudh Srinivasan #define PLL_LOCK_TIMEOUT_US	1000
41*23c8ebc9SAnirudh Srinivasan #define PLL_BYPASS_WAIT_US	500
42*23c8ebc9SAnirudh Srinivasan 
43*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_common {
44*23c8ebc9SAnirudh Srinivasan 	int clkid;
45*23c8ebc9SAnirudh Srinivasan 	struct regmap *regmap;
46*23c8ebc9SAnirudh Srinivasan 	struct clk_hw hw;
47*23c8ebc9SAnirudh Srinivasan };
48*23c8ebc9SAnirudh Srinivasan 
49*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_common *
50*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_common(struct clk_hw *hw)
51*23c8ebc9SAnirudh Srinivasan {
52*23c8ebc9SAnirudh Srinivasan 	return container_of(hw, struct atlantis_clk_common, hw);
53*23c8ebc9SAnirudh Srinivasan }
54*23c8ebc9SAnirudh Srinivasan 
55*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_mux_config {
56*23c8ebc9SAnirudh Srinivasan 	u8 shift;
57*23c8ebc9SAnirudh Srinivasan 	u8 width;
58*23c8ebc9SAnirudh Srinivasan 	u32 reg_offset;
59*23c8ebc9SAnirudh Srinivasan };
60*23c8ebc9SAnirudh Srinivasan 
61*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_mux {
62*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common common;
63*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_mux_config config;
64*23c8ebc9SAnirudh Srinivasan };
65*23c8ebc9SAnirudh Srinivasan 
66*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_config {
67*23c8ebc9SAnirudh Srinivasan 	u32 reg_offset;
68*23c8ebc9SAnirudh Srinivasan 	u32 enable;
69*23c8ebc9SAnirudh Srinivasan };
70*23c8ebc9SAnirudh Srinivasan 
71*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate {
72*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common common;
73*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_gate_config config;
74*23c8ebc9SAnirudh Srinivasan };
75*23c8ebc9SAnirudh Srinivasan 
76*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_divider_config {
77*23c8ebc9SAnirudh Srinivasan 	u8 shift;
78*23c8ebc9SAnirudh Srinivasan 	u8 width;
79*23c8ebc9SAnirudh Srinivasan 	u32 flags;
80*23c8ebc9SAnirudh Srinivasan 	u32 reg_offset;
81*23c8ebc9SAnirudh Srinivasan };
82*23c8ebc9SAnirudh Srinivasan 
83*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_divider {
84*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common common;
85*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_divider_config config;
86*23c8ebc9SAnirudh Srinivasan };
87*23c8ebc9SAnirudh Srinivasan 
88*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_pll_config {
89*23c8ebc9SAnirudh Srinivasan 	u32 tbl_num;
90*23c8ebc9SAnirudh Srinivasan 	u32 reg_offset;
91*23c8ebc9SAnirudh Srinivasan 	u32 en_reg_offset;
92*23c8ebc9SAnirudh Srinivasan 	u32 cg_reg_offset;
93*23c8ebc9SAnirudh Srinivasan 	u32 cg_reg_enable;
94*23c8ebc9SAnirudh Srinivasan };
95*23c8ebc9SAnirudh Srinivasan 
96*23c8ebc9SAnirudh Srinivasan /* Models a PLL with Bypass Functionality and Enable Bit + an optional Gate Clock at it's output */
97*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_pll {
98*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common common;
99*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_pll_config config;
100*23c8ebc9SAnirudh Srinivasan };
101*23c8ebc9SAnirudh Srinivasan 
102*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_shared_config {
103*23c8ebc9SAnirudh Srinivasan 	u32 reg_offset;
104*23c8ebc9SAnirudh Srinivasan 	u32 enable;
105*23c8ebc9SAnirudh Srinivasan 	unsigned int *share_count;
106*23c8ebc9SAnirudh Srinivasan 	spinlock_t *refcount_lock;
107*23c8ebc9SAnirudh Srinivasan };
108*23c8ebc9SAnirudh Srinivasan 
109*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_gate_shared {
110*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common common;
111*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_gate_shared_config config;
112*23c8ebc9SAnirudh Srinivasan };
113*23c8ebc9SAnirudh Srinivasan 
114*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_fixed_factor_config {
115*23c8ebc9SAnirudh Srinivasan 	unsigned int mult;
116*23c8ebc9SAnirudh Srinivasan 	unsigned int div;
117*23c8ebc9SAnirudh Srinivasan };
118*23c8ebc9SAnirudh Srinivasan 
119*23c8ebc9SAnirudh Srinivasan struct atlantis_clk_fixed_factor {
120*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_fixed_factor_config config;
121*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common common;
122*23c8ebc9SAnirudh Srinivasan };
123*23c8ebc9SAnirudh Srinivasan 
124*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_mux *hw_to_atlantis_clk_mux(struct clk_hw *hw)
125*23c8ebc9SAnirudh Srinivasan {
126*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw);
127*23c8ebc9SAnirudh Srinivasan 
128*23c8ebc9SAnirudh Srinivasan 	return container_of(common, struct atlantis_clk_mux, common);
129*23c8ebc9SAnirudh Srinivasan }
130*23c8ebc9SAnirudh Srinivasan 
131*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_gate *
132*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_gate(struct clk_hw *hw)
133*23c8ebc9SAnirudh Srinivasan {
134*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw);
135*23c8ebc9SAnirudh Srinivasan 
136*23c8ebc9SAnirudh Srinivasan 	return container_of(common, struct atlantis_clk_gate, common);
137*23c8ebc9SAnirudh Srinivasan }
138*23c8ebc9SAnirudh Srinivasan 
139*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_divider *
140*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_divider(struct clk_hw *hw)
141*23c8ebc9SAnirudh Srinivasan {
142*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw);
143*23c8ebc9SAnirudh Srinivasan 
144*23c8ebc9SAnirudh Srinivasan 	return container_of(common, struct atlantis_clk_divider, common);
145*23c8ebc9SAnirudh Srinivasan }
146*23c8ebc9SAnirudh Srinivasan 
147*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_pll *hw_to_atlantis_pll(struct clk_hw *hw)
148*23c8ebc9SAnirudh Srinivasan {
149*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw);
150*23c8ebc9SAnirudh Srinivasan 
151*23c8ebc9SAnirudh Srinivasan 	return container_of(common, struct atlantis_clk_pll, common);
152*23c8ebc9SAnirudh Srinivasan }
153*23c8ebc9SAnirudh Srinivasan 
154*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_gate_shared *
155*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_gate_shared(struct clk_hw *hw)
156*23c8ebc9SAnirudh Srinivasan {
157*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw);
158*23c8ebc9SAnirudh Srinivasan 
159*23c8ebc9SAnirudh Srinivasan 	return container_of(common, struct atlantis_clk_gate_shared, common);
160*23c8ebc9SAnirudh Srinivasan }
161*23c8ebc9SAnirudh Srinivasan 
162*23c8ebc9SAnirudh Srinivasan static inline struct atlantis_clk_fixed_factor *
163*23c8ebc9SAnirudh Srinivasan hw_to_atlantis_clk_fixed_factor(struct clk_hw *hw)
164*23c8ebc9SAnirudh Srinivasan {
165*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_common *common = hw_to_atlantis_clk_common(hw);
166*23c8ebc9SAnirudh Srinivasan 
167*23c8ebc9SAnirudh Srinivasan 	return container_of(common, struct atlantis_clk_fixed_factor, common);
168*23c8ebc9SAnirudh Srinivasan }
169*23c8ebc9SAnirudh Srinivasan 
170*23c8ebc9SAnirudh Srinivasan static u8 atlantis_clk_mux_get_parent(struct clk_hw *hw)
171*23c8ebc9SAnirudh Srinivasan {
172*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw);
173*23c8ebc9SAnirudh Srinivasan 	u32 val;
174*23c8ebc9SAnirudh Srinivasan 
175*23c8ebc9SAnirudh Srinivasan 	regmap_read(mux->common.regmap, mux->config.reg_offset, &val);
176*23c8ebc9SAnirudh Srinivasan 	val >>= mux->config.shift;
177*23c8ebc9SAnirudh Srinivasan 	val &= (BIT(mux->config.width) - 1);
178*23c8ebc9SAnirudh Srinivasan 
179*23c8ebc9SAnirudh Srinivasan 	return val;
180*23c8ebc9SAnirudh Srinivasan }
181*23c8ebc9SAnirudh Srinivasan 
182*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_mux_set_parent(struct clk_hw *hw, u8 index)
183*23c8ebc9SAnirudh Srinivasan {
184*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_mux *mux = hw_to_atlantis_clk_mux(hw);
185*23c8ebc9SAnirudh Srinivasan 	u32 val = index;
186*23c8ebc9SAnirudh Srinivasan 
187*23c8ebc9SAnirudh Srinivasan 	return regmap_update_bits(mux->common.regmap, mux->config.reg_offset,
188*23c8ebc9SAnirudh Srinivasan 				  (BIT(mux->config.width) - 1) << mux->config.shift,
189*23c8ebc9SAnirudh Srinivasan 				  val << mux->config.shift);
190*23c8ebc9SAnirudh Srinivasan }
191*23c8ebc9SAnirudh Srinivasan 
192*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_mux_determine_rate(struct clk_hw *hw,
193*23c8ebc9SAnirudh Srinivasan 					   struct clk_rate_request *req)
194*23c8ebc9SAnirudh Srinivasan {
195*23c8ebc9SAnirudh Srinivasan 	return clk_mux_determine_rate_flags(hw, req, hw->init->flags);
196*23c8ebc9SAnirudh Srinivasan }
197*23c8ebc9SAnirudh Srinivasan 
198*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_mux_ops = {
199*23c8ebc9SAnirudh Srinivasan 	.get_parent = atlantis_clk_mux_get_parent,
200*23c8ebc9SAnirudh Srinivasan 	.set_parent = atlantis_clk_mux_set_parent,
201*23c8ebc9SAnirudh Srinivasan 	.determine_rate = atlantis_clk_mux_determine_rate,
202*23c8ebc9SAnirudh Srinivasan };
203*23c8ebc9SAnirudh Srinivasan 
204*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_endisable(struct clk_hw *hw, int enable)
205*23c8ebc9SAnirudh Srinivasan {
206*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw);
207*23c8ebc9SAnirudh Srinivasan 
208*23c8ebc9SAnirudh Srinivasan 	if (enable)
209*23c8ebc9SAnirudh Srinivasan 		return regmap_set_bits(gate->common.regmap,
210*23c8ebc9SAnirudh Srinivasan 				       gate->config.reg_offset,
211*23c8ebc9SAnirudh Srinivasan 				       gate->config.enable);
212*23c8ebc9SAnirudh Srinivasan 	else
213*23c8ebc9SAnirudh Srinivasan 		return regmap_clear_bits(gate->common.regmap,
214*23c8ebc9SAnirudh Srinivasan 					 gate->config.reg_offset,
215*23c8ebc9SAnirudh Srinivasan 					 gate->config.enable);
216*23c8ebc9SAnirudh Srinivasan }
217*23c8ebc9SAnirudh Srinivasan 
218*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_enable(struct clk_hw *hw)
219*23c8ebc9SAnirudh Srinivasan {
220*23c8ebc9SAnirudh Srinivasan 	return atlantis_clk_gate_endisable(hw, 1);
221*23c8ebc9SAnirudh Srinivasan }
222*23c8ebc9SAnirudh Srinivasan 
223*23c8ebc9SAnirudh Srinivasan static void atlantis_clk_gate_disable(struct clk_hw *hw)
224*23c8ebc9SAnirudh Srinivasan {
225*23c8ebc9SAnirudh Srinivasan 	atlantis_clk_gate_endisable(hw, 0);
226*23c8ebc9SAnirudh Srinivasan }
227*23c8ebc9SAnirudh Srinivasan 
228*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_is_enabled(struct clk_hw *hw)
229*23c8ebc9SAnirudh Srinivasan {
230*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw);
231*23c8ebc9SAnirudh Srinivasan 
232*23c8ebc9SAnirudh Srinivasan 	return regmap_test_bits(gate->common.regmap, gate->config.reg_offset, gate->config.enable);
233*23c8ebc9SAnirudh Srinivasan }
234*23c8ebc9SAnirudh Srinivasan 
235*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_gate_ops = {
236*23c8ebc9SAnirudh Srinivasan 	.enable = atlantis_clk_gate_enable,
237*23c8ebc9SAnirudh Srinivasan 	.disable = atlantis_clk_gate_disable,
238*23c8ebc9SAnirudh Srinivasan 	.is_enabled = atlantis_clk_gate_is_enabled,
239*23c8ebc9SAnirudh Srinivasan };
240*23c8ebc9SAnirudh Srinivasan 
241*23c8ebc9SAnirudh Srinivasan static unsigned long atlantis_clk_divider_recalc_rate(struct clk_hw *hw,
242*23c8ebc9SAnirudh Srinivasan 						      unsigned long parent_rate)
243*23c8ebc9SAnirudh Srinivasan {
244*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_divider *divider = hw_to_atlantis_clk_divider(hw);
245*23c8ebc9SAnirudh Srinivasan 	u32 val;
246*23c8ebc9SAnirudh Srinivasan 
247*23c8ebc9SAnirudh Srinivasan 	regmap_read(divider->common.regmap, divider->config.reg_offset, &val);
248*23c8ebc9SAnirudh Srinivasan 
249*23c8ebc9SAnirudh Srinivasan 	val >>= divider->config.shift;
250*23c8ebc9SAnirudh Srinivasan 	val &= ((1 << (divider->config.width)) - 1);
251*23c8ebc9SAnirudh Srinivasan 
252*23c8ebc9SAnirudh Srinivasan 	return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1);
253*23c8ebc9SAnirudh Srinivasan }
254*23c8ebc9SAnirudh Srinivasan 
255*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_divider_ops = {
256*23c8ebc9SAnirudh Srinivasan 	.recalc_rate = atlantis_clk_divider_recalc_rate,
257*23c8ebc9SAnirudh Srinivasan };
258*23c8ebc9SAnirudh Srinivasan 
259*23c8ebc9SAnirudh Srinivasan static unsigned long
260*23c8ebc9SAnirudh Srinivasan atlantis_clk_fixed_factor_recalc_rate(struct clk_hw *hw,
261*23c8ebc9SAnirudh Srinivasan 				      unsigned long parent_rate)
262*23c8ebc9SAnirudh Srinivasan {
263*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_fixed_factor *factor =
264*23c8ebc9SAnirudh Srinivasan 		hw_to_atlantis_clk_fixed_factor(hw);
265*23c8ebc9SAnirudh Srinivasan 	unsigned long long rate;
266*23c8ebc9SAnirudh Srinivasan 
267*23c8ebc9SAnirudh Srinivasan 	rate = (unsigned long long)parent_rate * factor->config.mult;
268*23c8ebc9SAnirudh Srinivasan 	do_div(rate, factor->config.div);
269*23c8ebc9SAnirudh Srinivasan 
270*23c8ebc9SAnirudh Srinivasan 	return (unsigned long)rate;
271*23c8ebc9SAnirudh Srinivasan }
272*23c8ebc9SAnirudh Srinivasan 
273*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_fixed_factor_ops = {
274*23c8ebc9SAnirudh Srinivasan 	.recalc_rate = atlantis_clk_fixed_factor_recalc_rate,
275*23c8ebc9SAnirudh Srinivasan };
276*23c8ebc9SAnirudh Srinivasan 
277*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_pll_is_enabled(struct clk_hw *hw)
278*23c8ebc9SAnirudh Srinivasan {
279*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw);
280*23c8ebc9SAnirudh Srinivasan 	u32 val, en_val, cg_val;
281*23c8ebc9SAnirudh Srinivasan 
282*23c8ebc9SAnirudh Srinivasan 	regmap_read(pll->common.regmap, pll->config.reg_offset, &val);
283*23c8ebc9SAnirudh Srinivasan 	regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val);
284*23c8ebc9SAnirudh Srinivasan 	regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val);
285*23c8ebc9SAnirudh Srinivasan 
286*23c8ebc9SAnirudh Srinivasan 	/* Check if PLL is powered on, locked, not bypassed and Gate clk is enabled */
287*23c8ebc9SAnirudh Srinivasan 	return !!(en_val & PLL_CFG_EN_BIT) && !!(val & PLL_CFG_LOCK_BIT) &&
288*23c8ebc9SAnirudh Srinivasan 	       (!pll->config.cg_reg_enable || (cg_val & pll->config.cg_reg_enable)) &&
289*23c8ebc9SAnirudh Srinivasan 	       !(val & PLL_CFG_BYPASS_BIT);
290*23c8ebc9SAnirudh Srinivasan }
291*23c8ebc9SAnirudh Srinivasan 
292*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_pll_enable(struct clk_hw *hw)
293*23c8ebc9SAnirudh Srinivasan {
294*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw);
295*23c8ebc9SAnirudh Srinivasan 	u32 val, en_val, cg_val;
296*23c8ebc9SAnirudh Srinivasan 	int ret;
297*23c8ebc9SAnirudh Srinivasan 
298*23c8ebc9SAnirudh Srinivasan 	regmap_read(pll->common.regmap, pll->config.reg_offset, &val);
299*23c8ebc9SAnirudh Srinivasan 	regmap_read(pll->common.regmap, pll->config.en_reg_offset, &en_val);
300*23c8ebc9SAnirudh Srinivasan 	regmap_read(pll->common.regmap, pll->config.cg_reg_offset, &cg_val);
301*23c8ebc9SAnirudh Srinivasan 
302*23c8ebc9SAnirudh Srinivasan 	/* Check if PLL is already enabled, locked, not bypassed and Gate clk is enabled */
303*23c8ebc9SAnirudh Srinivasan 	if ((en_val & PLL_CFG_EN_BIT) && (val & PLL_CFG_LOCK_BIT) &&
304*23c8ebc9SAnirudh Srinivasan 	    (!pll->config.cg_reg_enable || (cg_val & pll->config.cg_reg_enable)) &&
305*23c8ebc9SAnirudh Srinivasan 	    !(val & PLL_CFG_BYPASS_BIT)) {
306*23c8ebc9SAnirudh Srinivasan 		return 0;
307*23c8ebc9SAnirudh Srinivasan 	}
308*23c8ebc9SAnirudh Srinivasan 
309*23c8ebc9SAnirudh Srinivasan 	/* Step 1: Set bypass mode first */
310*23c8ebc9SAnirudh Srinivasan 	regmap_update_bits(pll->common.regmap, pll->config.reg_offset,
311*23c8ebc9SAnirudh Srinivasan 			   PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT);
312*23c8ebc9SAnirudh Srinivasan 
313*23c8ebc9SAnirudh Srinivasan 	/* Step 2: Enable PLL (clear then set power bit) */
314*23c8ebc9SAnirudh Srinivasan 	regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset,
315*23c8ebc9SAnirudh Srinivasan 			   PLL_CFG_EN_BIT, 0);
316*23c8ebc9SAnirudh Srinivasan 
317*23c8ebc9SAnirudh Srinivasan 	regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset,
318*23c8ebc9SAnirudh Srinivasan 			   PLL_CFG_EN_BIT, PLL_CFG_EN_BIT);
319*23c8ebc9SAnirudh Srinivasan 
320*23c8ebc9SAnirudh Srinivasan 	/* Step 3: Wait for PLL lock */
321*23c8ebc9SAnirudh Srinivasan 	ret = regmap_read_poll_timeout(pll->common.regmap,
322*23c8ebc9SAnirudh Srinivasan 				       pll->config.reg_offset, val,
323*23c8ebc9SAnirudh Srinivasan 				       val & PLL_CFG_LOCK_BIT,
324*23c8ebc9SAnirudh Srinivasan 				       PLL_BYPASS_WAIT_US, PLL_LOCK_TIMEOUT_US);
325*23c8ebc9SAnirudh Srinivasan 	if (ret) {
326*23c8ebc9SAnirudh Srinivasan 		pr_err("PLL failed to lock within timeout\n");
327*23c8ebc9SAnirudh Srinivasan 		return ret;
328*23c8ebc9SAnirudh Srinivasan 	}
329*23c8ebc9SAnirudh Srinivasan 
330*23c8ebc9SAnirudh Srinivasan 	/* Step 4: Switch from bypass to PLL output */
331*23c8ebc9SAnirudh Srinivasan 	regmap_update_bits(pll->common.regmap, pll->config.reg_offset,
332*23c8ebc9SAnirudh Srinivasan 			   PLL_CFG_BYPASS_BIT, 0);
333*23c8ebc9SAnirudh Srinivasan 
334*23c8ebc9SAnirudh Srinivasan 	/* Enable Gate clk at PLL Output */
335*23c8ebc9SAnirudh Srinivasan 	return regmap_update_bits(pll->common.regmap, pll->config.cg_reg_offset,
336*23c8ebc9SAnirudh Srinivasan 				  pll->config.cg_reg_enable,
337*23c8ebc9SAnirudh Srinivasan 				  pll->config.cg_reg_enable);
338*23c8ebc9SAnirudh Srinivasan }
339*23c8ebc9SAnirudh Srinivasan 
340*23c8ebc9SAnirudh Srinivasan static void atlantis_clk_pll_disable(struct clk_hw *hw)
341*23c8ebc9SAnirudh Srinivasan {
342*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw);
343*23c8ebc9SAnirudh Srinivasan 
344*23c8ebc9SAnirudh Srinivasan 	/* Step 1: Switch to bypass mode before disabling */
345*23c8ebc9SAnirudh Srinivasan 	regmap_update_bits(pll->common.regmap, pll->config.reg_offset,
346*23c8ebc9SAnirudh Srinivasan 			   PLL_CFG_BYPASS_BIT, PLL_CFG_BYPASS_BIT);
347*23c8ebc9SAnirudh Srinivasan 	/* Step 2: Power down PLL */
348*23c8ebc9SAnirudh Srinivasan 	regmap_update_bits(pll->common.regmap, pll->config.en_reg_offset,
349*23c8ebc9SAnirudh Srinivasan 			   PLL_CFG_EN_BIT, 0);
350*23c8ebc9SAnirudh Srinivasan }
351*23c8ebc9SAnirudh Srinivasan 
352*23c8ebc9SAnirudh Srinivasan static unsigned long atlantis_clk_pll_recalc_rate(struct clk_hw *hw,
353*23c8ebc9SAnirudh Srinivasan 						  unsigned long parent_rate)
354*23c8ebc9SAnirudh Srinivasan {
355*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_pll *pll = hw_to_atlantis_pll(hw);
356*23c8ebc9SAnirudh Srinivasan 
357*23c8ebc9SAnirudh Srinivasan 	u32 val, refdiv, fbdiv, postdiv1, postdiv2;
358*23c8ebc9SAnirudh Srinivasan 	u64 fout;
359*23c8ebc9SAnirudh Srinivasan 
360*23c8ebc9SAnirudh Srinivasan 	regmap_read(pll->common.regmap, pll->config.reg_offset, &val);
361*23c8ebc9SAnirudh Srinivasan 
362*23c8ebc9SAnirudh Srinivasan 	if (val & PLL_CFG_BYPASS_BIT)
363*23c8ebc9SAnirudh Srinivasan 		return parent_rate;
364*23c8ebc9SAnirudh Srinivasan 
365*23c8ebc9SAnirudh Srinivasan 	refdiv = FIELD_GET(PLL_CFG_REFDIV_MASK, val);
366*23c8ebc9SAnirudh Srinivasan 	fbdiv = FIELD_GET(PLL_CFG_FBDIV_MASK, val);
367*23c8ebc9SAnirudh Srinivasan 	postdiv1 = FIELD_GET(PLL_CFG_POSTDIV1_MASK, val);
368*23c8ebc9SAnirudh Srinivasan 	postdiv2 = FIELD_GET(PLL_CFG_POSTDIV2_MASK, val);
369*23c8ebc9SAnirudh Srinivasan 
370*23c8ebc9SAnirudh Srinivasan 	if (!refdiv)
371*23c8ebc9SAnirudh Srinivasan 		refdiv = 1;
372*23c8ebc9SAnirudh Srinivasan 	if (!postdiv1)
373*23c8ebc9SAnirudh Srinivasan 		postdiv1 = 1;
374*23c8ebc9SAnirudh Srinivasan 	if (!postdiv2)
375*23c8ebc9SAnirudh Srinivasan 		postdiv2 = 1;
376*23c8ebc9SAnirudh Srinivasan 	if (!fbdiv)
377*23c8ebc9SAnirudh Srinivasan 		return 0;
378*23c8ebc9SAnirudh Srinivasan 
379*23c8ebc9SAnirudh Srinivasan 	fout = div64_u64((u64)parent_rate * fbdiv,
380*23c8ebc9SAnirudh Srinivasan 			 refdiv * postdiv1 * postdiv2);
381*23c8ebc9SAnirudh Srinivasan 
382*23c8ebc9SAnirudh Srinivasan 	return fout;
383*23c8ebc9SAnirudh Srinivasan }
384*23c8ebc9SAnirudh Srinivasan 
385*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_pll_ops = {
386*23c8ebc9SAnirudh Srinivasan 	.enable = atlantis_clk_pll_enable,
387*23c8ebc9SAnirudh Srinivasan 	.disable = atlantis_clk_pll_disable,
388*23c8ebc9SAnirudh Srinivasan 	.recalc_rate = atlantis_clk_pll_recalc_rate,
389*23c8ebc9SAnirudh Srinivasan 	.is_enabled = atlantis_clk_pll_is_enabled,
390*23c8ebc9SAnirudh Srinivasan };
391*23c8ebc9SAnirudh Srinivasan 
392*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_shared_enable(struct clk_hw *hw)
393*23c8ebc9SAnirudh Srinivasan {
394*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_gate_shared *gate =
395*23c8ebc9SAnirudh Srinivasan 		hw_to_atlantis_clk_gate_shared(hw);
396*23c8ebc9SAnirudh Srinivasan 	bool need_enable;
397*23c8ebc9SAnirudh Srinivasan 
398*23c8ebc9SAnirudh Srinivasan 	scoped_guard(spinlock_irqsave, gate->config.refcount_lock)
399*23c8ebc9SAnirudh Srinivasan 	{
400*23c8ebc9SAnirudh Srinivasan 		need_enable = (*gate->config.share_count)++ == 0;
401*23c8ebc9SAnirudh Srinivasan 		if (need_enable) {
402*23c8ebc9SAnirudh Srinivasan 			regmap_set_bits(gate->common.regmap,
403*23c8ebc9SAnirudh Srinivasan 					gate->config.reg_offset,
404*23c8ebc9SAnirudh Srinivasan 					gate->config.enable);
405*23c8ebc9SAnirudh Srinivasan 		}
406*23c8ebc9SAnirudh Srinivasan 	}
407*23c8ebc9SAnirudh Srinivasan 
408*23c8ebc9SAnirudh Srinivasan 	if (need_enable) {
409*23c8ebc9SAnirudh Srinivasan 		if (!regmap_test_bits(gate->common.regmap,
410*23c8ebc9SAnirudh Srinivasan 				      gate->config.reg_offset,
411*23c8ebc9SAnirudh Srinivasan 				      gate->config.enable)) {
412*23c8ebc9SAnirudh Srinivasan 			pr_warn("%s: gate enable %d failed to enable\n",
413*23c8ebc9SAnirudh Srinivasan 				clk_hw_get_name(hw), gate->config.enable);
414*23c8ebc9SAnirudh Srinivasan 			return -EIO;
415*23c8ebc9SAnirudh Srinivasan 		}
416*23c8ebc9SAnirudh Srinivasan 	}
417*23c8ebc9SAnirudh Srinivasan 
418*23c8ebc9SAnirudh Srinivasan 	return 0;
419*23c8ebc9SAnirudh Srinivasan }
420*23c8ebc9SAnirudh Srinivasan 
421*23c8ebc9SAnirudh Srinivasan static void atlantis_clk_gate_shared_disable(struct clk_hw *hw)
422*23c8ebc9SAnirudh Srinivasan {
423*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_gate_shared *gate =
424*23c8ebc9SAnirudh Srinivasan 		hw_to_atlantis_clk_gate_shared(hw);
425*23c8ebc9SAnirudh Srinivasan 
426*23c8ebc9SAnirudh Srinivasan 	scoped_guard(spinlock_irqsave, gate->config.refcount_lock)
427*23c8ebc9SAnirudh Srinivasan 	{
428*23c8ebc9SAnirudh Srinivasan 		if (WARN_ON(*gate->config.share_count == 0))
429*23c8ebc9SAnirudh Srinivasan 			return;
430*23c8ebc9SAnirudh Srinivasan 		if (--(*gate->config.share_count) > 0)
431*23c8ebc9SAnirudh Srinivasan 			return;
432*23c8ebc9SAnirudh Srinivasan 
433*23c8ebc9SAnirudh Srinivasan 		regmap_clear_bits(gate->common.regmap,
434*23c8ebc9SAnirudh Srinivasan 				  gate->config.reg_offset,
435*23c8ebc9SAnirudh Srinivasan 				  gate->config.enable);
436*23c8ebc9SAnirudh Srinivasan 	}
437*23c8ebc9SAnirudh Srinivasan }
438*23c8ebc9SAnirudh Srinivasan 
439*23c8ebc9SAnirudh Srinivasan static int atlantis_clk_gate_shared_is_enabled(struct clk_hw *hw)
440*23c8ebc9SAnirudh Srinivasan {
441*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_gate_shared *gate =
442*23c8ebc9SAnirudh Srinivasan 		hw_to_atlantis_clk_gate_shared(hw);
443*23c8ebc9SAnirudh Srinivasan 
444*23c8ebc9SAnirudh Srinivasan 	return regmap_test_bits(gate->common.regmap, gate->config.reg_offset, gate->config.enable);
445*23c8ebc9SAnirudh Srinivasan }
446*23c8ebc9SAnirudh Srinivasan 
447*23c8ebc9SAnirudh Srinivasan static void atlantis_clk_gate_shared_disable_unused(struct clk_hw *hw)
448*23c8ebc9SAnirudh Srinivasan {
449*23c8ebc9SAnirudh Srinivasan 	struct atlantis_clk_gate_shared *gate =
450*23c8ebc9SAnirudh Srinivasan 		hw_to_atlantis_clk_gate_shared(hw);
451*23c8ebc9SAnirudh Srinivasan 
452*23c8ebc9SAnirudh Srinivasan 	scoped_guard(spinlock_irqsave, gate->config.refcount_lock)
453*23c8ebc9SAnirudh Srinivasan 	{
454*23c8ebc9SAnirudh Srinivasan 		if (*gate->config.share_count == 0)
455*23c8ebc9SAnirudh Srinivasan 			regmap_clear_bits(gate->common.regmap,
456*23c8ebc9SAnirudh Srinivasan 					  gate->config.reg_offset,
457*23c8ebc9SAnirudh Srinivasan 					  gate->config.enable);
458*23c8ebc9SAnirudh Srinivasan 	}
459*23c8ebc9SAnirudh Srinivasan }
460*23c8ebc9SAnirudh Srinivasan 
461*23c8ebc9SAnirudh Srinivasan static const struct clk_ops atlantis_clk_gate_shared_ops = {
462*23c8ebc9SAnirudh Srinivasan 	.enable = atlantis_clk_gate_shared_enable,
463*23c8ebc9SAnirudh Srinivasan 	.disable = atlantis_clk_gate_shared_disable,
464*23c8ebc9SAnirudh Srinivasan 	.disable_unused = atlantis_clk_gate_shared_disable_unused,
465*23c8ebc9SAnirudh Srinivasan 	.is_enabled = atlantis_clk_gate_shared_is_enabled,
466*23c8ebc9SAnirudh Srinivasan };
467*23c8ebc9SAnirudh Srinivasan 
468*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset, _cg_reg_offset, \
469*23c8ebc9SAnirudh Srinivasan 			    _cg_reg_enable)                              \
470*23c8ebc9SAnirudh Srinivasan 	{                                                                \
471*23c8ebc9SAnirudh Srinivasan 		.reg_offset = (_reg_offset),                             \
472*23c8ebc9SAnirudh Srinivasan 		.en_reg_offset = (_en_reg_offset),                       \
473*23c8ebc9SAnirudh Srinivasan 		.cg_reg_offset = (_cg_reg_offset),                       \
474*23c8ebc9SAnirudh Srinivasan 		.cg_reg_enable = (_cg_reg_enable),                       \
475*23c8ebc9SAnirudh Srinivasan 	}
476*23c8ebc9SAnirudh Srinivasan 
477*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_PLL_DEFINE(_clkid, _name, _parent, _reg_offset,               \
478*23c8ebc9SAnirudh Srinivasan 			    _en_reg_offset, _cg_reg_offset, _cg_reg_enable,    \
479*23c8ebc9SAnirudh Srinivasan 			    _flags)                                            \
480*23c8ebc9SAnirudh Srinivasan 	static struct atlantis_clk_pll _name = {                               \
481*23c8ebc9SAnirudh Srinivasan 		.config = ATLANTIS_PLL_CONFIG(_reg_offset, _en_reg_offset,     \
482*23c8ebc9SAnirudh Srinivasan 					      _cg_reg_offset, _cg_reg_enable), \
483*23c8ebc9SAnirudh Srinivasan 		.common = { .clkid = _clkid,                                   \
484*23c8ebc9SAnirudh Srinivasan 			    .hw.init = CLK_HW_INIT_PARENTS_DATA(               \
485*23c8ebc9SAnirudh Srinivasan 				    #_name, _parent, &atlantis_clk_pll_ops,    \
486*23c8ebc9SAnirudh Srinivasan 				    _flags) },                                 \
487*23c8ebc9SAnirudh Srinivasan 	}
488*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset)                    \
489*23c8ebc9SAnirudh Srinivasan 	{                                                                   \
490*23c8ebc9SAnirudh Srinivasan 		.shift = _shift, .width = _width, .reg_offset = _reg_offset \
491*23c8ebc9SAnirudh Srinivasan 	}
492*23c8ebc9SAnirudh Srinivasan 
493*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_MUX_DEFINE(_clkid, _name, _parents, _reg_offset, _shift,    \
494*23c8ebc9SAnirudh Srinivasan 			    _width, _flags)                                  \
495*23c8ebc9SAnirudh Srinivasan 	static struct atlantis_clk_mux _name = {                             \
496*23c8ebc9SAnirudh Srinivasan 		.config = ATLANTIS_MUX_CONFIG(_shift, _width, _reg_offset),  \
497*23c8ebc9SAnirudh Srinivasan 		.common = { .clkid = _clkid,                                 \
498*23c8ebc9SAnirudh Srinivasan 			    .hw.init = CLK_HW_INIT_PARENTS_DATA(             \
499*23c8ebc9SAnirudh Srinivasan 				    #_name, _parents, &atlantis_clk_mux_ops, \
500*23c8ebc9SAnirudh Srinivasan 				    _flags) }                                \
501*23c8ebc9SAnirudh Srinivasan 	}
502*23c8ebc9SAnirudh Srinivasan 
503*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_DIVIDER_CONFIG(_shift, _width, _flags, _reg_offset) \
504*23c8ebc9SAnirudh Srinivasan 	{                                                            \
505*23c8ebc9SAnirudh Srinivasan 		.shift = _shift, .width = _width, .flags = _flags,   \
506*23c8ebc9SAnirudh Srinivasan 		.reg_offset = _reg_offset                            \
507*23c8ebc9SAnirudh Srinivasan 	}
508*23c8ebc9SAnirudh Srinivasan 
509*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_DIVIDER_DEFINE(_clkid, _name, _parent, _reg_offset, _shift, \
510*23c8ebc9SAnirudh Srinivasan 				_width, _divflags, _flags)                   \
511*23c8ebc9SAnirudh Srinivasan 	static struct atlantis_clk_divider _name = {                         \
512*23c8ebc9SAnirudh Srinivasan 		.config = ATLANTIS_DIVIDER_CONFIG(_shift, _width, _divflags, \
513*23c8ebc9SAnirudh Srinivasan 						  _reg_offset),              \
514*23c8ebc9SAnirudh Srinivasan 		.common = { .clkid = _clkid,                                 \
515*23c8ebc9SAnirudh Srinivasan 			    .hw.init = CLK_HW_INIT_HW(                       \
516*23c8ebc9SAnirudh Srinivasan 				    #_name, &_parent.common.hw,              \
517*23c8ebc9SAnirudh Srinivasan 				    &atlantis_clk_divider_ops, _flags) }     \
518*23c8ebc9SAnirudh Srinivasan 	}
519*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_GATE_CONFIG(_enable, _reg_offset)           \
520*23c8ebc9SAnirudh Srinivasan 	{                                                    \
521*23c8ebc9SAnirudh Srinivasan 		.enable = _enable, .reg_offset = _reg_offset \
522*23c8ebc9SAnirudh Srinivasan 	}
523*23c8ebc9SAnirudh Srinivasan 
524*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_GATE_DEFINE(_clkid, _name, _parent, _reg_offset, _enable, \
525*23c8ebc9SAnirudh Srinivasan 			     _flags)                                       \
526*23c8ebc9SAnirudh Srinivasan 	static struct atlantis_clk_gate _name = {                          \
527*23c8ebc9SAnirudh Srinivasan 		.config = ATLANTIS_GATE_CONFIG(_enable, _reg_offset),      \
528*23c8ebc9SAnirudh Srinivasan 		.common = { .clkid = _clkid,                               \
529*23c8ebc9SAnirudh Srinivasan 			    .hw.init = CLK_HW_INIT_HW(                     \
530*23c8ebc9SAnirudh Srinivasan 				    #_name, &_parent.common.hw,            \
531*23c8ebc9SAnirudh Srinivasan 				    &atlantis_clk_gate_ops, _flags) }      \
532*23c8ebc9SAnirudh Srinivasan 	}
533*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable, _share_count)      \
534*23c8ebc9SAnirudh Srinivasan 	{                                                                    \
535*23c8ebc9SAnirudh Srinivasan 		.reg_offset = _reg_offset, .enable = _enable,                \
536*23c8ebc9SAnirudh Srinivasan 		.share_count = _share_count, .refcount_lock = &refcount_lock \
537*23c8ebc9SAnirudh Srinivasan 	}
538*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_GATE_SHARED_DEFINE(_clkid, _name, _parent, _reg_offset,     \
539*23c8ebc9SAnirudh Srinivasan 				    _enable, _share_count, _flags)           \
540*23c8ebc9SAnirudh Srinivasan 	static struct atlantis_clk_gate_shared _name = {                     \
541*23c8ebc9SAnirudh Srinivasan 		.config = ATLANTIS_GATE_SHARED_CONFIG(_reg_offset, _enable,  \
542*23c8ebc9SAnirudh Srinivasan 						      _share_count),         \
543*23c8ebc9SAnirudh Srinivasan 		.common = { .clkid = _clkid,                                 \
544*23c8ebc9SAnirudh Srinivasan 			    .hw.init = CLK_HW_INIT_HW(                       \
545*23c8ebc9SAnirudh Srinivasan 				    #_name, &_parent.common.hw,              \
546*23c8ebc9SAnirudh Srinivasan 				    &atlantis_clk_gate_shared_ops, _flags) } \
547*23c8ebc9SAnirudh Srinivasan 	}
548*23c8ebc9SAnirudh Srinivasan #define ATLANTIS_FIXED_FACTOR_DEFINE(_clkid, _name, _parent, _mult, _div,     \
549*23c8ebc9SAnirudh Srinivasan 				     _flags)                                  \
550*23c8ebc9SAnirudh Srinivasan 	static struct atlantis_clk_fixed_factor _name = {                     \
551*23c8ebc9SAnirudh Srinivasan 		.config = { .mult = _mult, .div = _div },                     \
552*23c8ebc9SAnirudh Srinivasan 		.common = { .clkid = _clkid,                                  \
553*23c8ebc9SAnirudh Srinivasan 			    .hw.init = CLK_HW_INIT_HW(                        \
554*23c8ebc9SAnirudh Srinivasan 				    #_name, &_parent.common.hw,               \
555*23c8ebc9SAnirudh Srinivasan 				    &atlantis_clk_fixed_factor_ops, _flags) } \
556*23c8ebc9SAnirudh Srinivasan 	}
557*23c8ebc9SAnirudh Srinivasan 
558*23c8ebc9SAnirudh Srinivasan static DEFINE_SPINLOCK(refcount_lock); /* Lock for refcount value accesses */
559*23c8ebc9SAnirudh Srinivasan 
560*23c8ebc9SAnirudh Srinivasan static const struct regmap_config atlantis_prcm_regmap_config = {
561*23c8ebc9SAnirudh Srinivasan 	.reg_bits = 32,
562*23c8ebc9SAnirudh Srinivasan 	.reg_stride = 4,
563*23c8ebc9SAnirudh Srinivasan 	.val_bits = 32,
564*23c8ebc9SAnirudh Srinivasan 	.max_register = 0xFFFC,
565*23c8ebc9SAnirudh Srinivasan 	.cache_type = REGCACHE_NONE,
566*23c8ebc9SAnirudh Srinivasan };
567*23c8ebc9SAnirudh Srinivasan 
568*23c8ebc9SAnirudh Srinivasan struct atlantis_prcm_data {
569*23c8ebc9SAnirudh Srinivasan 	struct clk_hw **hws;
570*23c8ebc9SAnirudh Srinivasan 	size_t num;
571*23c8ebc9SAnirudh Srinivasan 	const char *reset_name;
572*23c8ebc9SAnirudh Srinivasan };
573*23c8ebc9SAnirudh Srinivasan 
574*23c8ebc9SAnirudh Srinivasan static const struct clk_parent_data osc_24m_clk[] = {
575*23c8ebc9SAnirudh Srinivasan 	{ .index = 0 },
576*23c8ebc9SAnirudh Srinivasan };
577*23c8ebc9SAnirudh Srinivasan 
578*23c8ebc9SAnirudh Srinivasan ATLANTIS_PLL_DEFINE(CLK_RCPU_PLL, rcpu_pll_clk, osc_24m_clk, PLL_RCPU_CFG_REG,
579*23c8ebc9SAnirudh Srinivasan 		    PLL_RCPU_EN_REG, BUS_CG_REG, 0, /* No Gate Clk at Output */
580*23c8ebc9SAnirudh Srinivasan 		    CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL);
581*23c8ebc9SAnirudh Srinivasan 
582*23c8ebc9SAnirudh Srinivasan static const struct clk_parent_data rcpu_root_parents[] = {
583*23c8ebc9SAnirudh Srinivasan 	{ .index = 0 },
584*23c8ebc9SAnirudh Srinivasan 	{ .hw = &rcpu_pll_clk.common.hw },
585*23c8ebc9SAnirudh Srinivasan };
586*23c8ebc9SAnirudh Srinivasan 
587*23c8ebc9SAnirudh Srinivasan ATLANTIS_MUX_DEFINE(CLK_RCPU_ROOT, rcpu_root_clk, rcpu_root_parents,
588*23c8ebc9SAnirudh Srinivasan 		    RCPU_DIV_CFG_REG, 0, 1, CLK_SET_RATE_NO_REPARENT);
589*23c8ebc9SAnirudh Srinivasan 
590*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV2, rcpu_div2_clk, rcpu_root_clk,
591*23c8ebc9SAnirudh Srinivasan 			RCPU_DIV_CFG_REG, 2, 4, 0, 0);
592*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_DIV4, rcpu_div4_clk, rcpu_root_clk,
593*23c8ebc9SAnirudh Srinivasan 			RCPU_DIV_CFG_REG, 7, 4, 0, 0);
594*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_RCPU_RTC, rcpu_rtc_clk, rcpu_div4_clk,
595*23c8ebc9SAnirudh Srinivasan 			RCPU_DIV_CFG_REG, 12, 6, 0, 0);
596*23c8ebc9SAnirudh Srinivasan 
597*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SMNDMA0_ACLK, rcpu_dma0_clk, rcpu_div2_clk,
598*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(0), 0);
599*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SMNDMA1_ACLK, rcpu_dma1_clk, rcpu_div2_clk,
600*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(1), 0);
601*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_WDT0_PCLK, sl_wdt0_pclk, rcpu_div4_clk,
602*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(2), 0);
603*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_WDT1_PCLK, sl_wdt1_pclk, rcpu_div4_clk,
604*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(3), 0);
605*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_TIMER_PCLK, sl_timer_pclk, rcpu_div4_clk,
606*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(4), 0);
607*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_PVTC_PCLK, sl_pvtc_pclk, rcpu_div4_clk,
608*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(12), 0);
609*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_PMU_PCLK, sl_pmu_pclk, rcpu_div4_clk, RCPU_BLK_CG_REG,
610*23c8ebc9SAnirudh Srinivasan 		     BIT(13), 0);
611*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_MAILBOX_HCLK, rcpu_ipc_clk, rcpu_div2_clk,
612*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(14), 0);
613*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SEC_SPACC_HCLK, sec_spacc_hclk, rcpu_div2_clk,
614*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(26), 0);
615*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SEC_OTP_HCLK, sec_otp_hclk, rcpu_div2_clk,
616*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(28), 0);
617*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_TRNG_PCLK, sec_trng_pclk, rcpu_div4_clk,
618*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(29), 0);
619*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SEC_CRC_HCLK, sec_crc_hclk, rcpu_div2_clk,
620*23c8ebc9SAnirudh Srinivasan 		     RCPU_BLK_CG_REG, BIT(30), 0);
621*23c8ebc9SAnirudh Srinivasan 
622*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_HCLK, rcpu_smn_hclk, rcpu_div2_clk, 1, 1,
623*23c8ebc9SAnirudh Srinivasan 			     0);
624*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_AHB0_HCLK, rcpu_ahb0_hclk, rcpu_div2_clk, 1, 1,
625*23c8ebc9SAnirudh Srinivasan 			     0);
626*23c8ebc9SAnirudh Srinivasan 
627*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_PCLK, rcpu_smn_pclk, rcpu_div4_clk, 1, 1,
628*23c8ebc9SAnirudh Srinivasan 			     0);
629*23c8ebc9SAnirudh Srinivasan 
630*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SMN_CLK, rcpu_smn_clk, rcpu_root_clk, 1, 1, 0);
631*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_SCRATCHPAD_CLK, rcpu_scratchpad_aclk,
632*23c8ebc9SAnirudh Srinivasan 			     rcpu_root_clk, 1, 1, 0);
633*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_RCPU_CORE_CLK, rcpu_core_clk, rcpu_root_clk, 1,
634*23c8ebc9SAnirudh Srinivasan 			     1, 0);
635*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_RCPU_ROM_CLK, rcpu_rom_aclk, rcpu_root_clk, 1,
636*23c8ebc9SAnirudh Srinivasan 			     1, 0);
637*23c8ebc9SAnirudh Srinivasan 
638*23c8ebc9SAnirudh Srinivasan static struct atlantis_clk_fixed_factor
639*23c8ebc9SAnirudh Srinivasan 	otp_load_clk = { .config = { .mult = 1, .div = 1 },
640*23c8ebc9SAnirudh Srinivasan 			 .common = {
641*23c8ebc9SAnirudh Srinivasan 				 .clkid = CLK_OTP_LOAD_CLK,
642*23c8ebc9SAnirudh Srinivasan 				 .hw.init = CLK_HW_INIT_PARENTS_DATA(
643*23c8ebc9SAnirudh Srinivasan 					 "otp_load_clk", osc_24m_clk,
644*23c8ebc9SAnirudh Srinivasan 					 &atlantis_clk_fixed_factor_ops,
645*23c8ebc9SAnirudh Srinivasan 					 CLK_SET_RATE_NO_REPARENT),
646*23c8ebc9SAnirudh Srinivasan 			 } };
647*23c8ebc9SAnirudh Srinivasan 
648*23c8ebc9SAnirudh Srinivasan ATLANTIS_PLL_DEFINE(CLK_NOC_PLL, nocc_pll_clk, osc_24m_clk, PLL_NOCC_CFG_REG,
649*23c8ebc9SAnirudh Srinivasan 		    PLL_NOCC_EN_REG, BUS_CG_REG, BIT(0),
650*23c8ebc9SAnirudh Srinivasan 		    CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL);
651*23c8ebc9SAnirudh Srinivasan 
652*23c8ebc9SAnirudh Srinivasan static const struct clk_parent_data nocc_mux_parents[] = {
653*23c8ebc9SAnirudh Srinivasan 	{ .index = 0 },
654*23c8ebc9SAnirudh Srinivasan 	{ .hw = &nocc_pll_clk.common.hw },
655*23c8ebc9SAnirudh Srinivasan };
656*23c8ebc9SAnirudh Srinivasan 
657*23c8ebc9SAnirudh Srinivasan ATLANTIS_MUX_DEFINE(CLK_NOCC_CLK, nocc_clk, nocc_mux_parents, NOCC_CLK_CFG_REG,
658*23c8ebc9SAnirudh Srinivasan 		    0, 1, CLK_SET_RATE_NO_REPARENT);
659*23c8ebc9SAnirudh Srinivasan 
660*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV2, nocc_div2_clk, nocc_clk,
661*23c8ebc9SAnirudh Srinivasan 			NOCC_CLK_CFG_REG, 1, 4, 0, 0);
662*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_DIV4, nocc_div4_clk, nocc_clk,
663*23c8ebc9SAnirudh Srinivasan 			NOCC_CLK_CFG_REG, 5, 4, 0, 0);
664*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_RTC, nocc_rtc_clk, nocc_div4_clk,
665*23c8ebc9SAnirudh Srinivasan 			NOCC_CLK_CFG_REG, 9, 6, 0, 0);
666*23c8ebc9SAnirudh Srinivasan ATLANTIS_DIVIDER_DEFINE(CLK_NOCC_CAN, nocc_can_clk, nocc_clk, NOCC_CLK_CFG_REG,
667*23c8ebc9SAnirudh Srinivasan 			15, 4, 0, 0);
668*23c8ebc9SAnirudh Srinivasan 
669*23c8ebc9SAnirudh Srinivasan static unsigned int refcnt_qspi;
670*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_SCLK, lsio_qspi_sclk, nocc_clk,
671*23c8ebc9SAnirudh Srinivasan 			    LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0);
672*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_QSPI_HCLK, lsio_qspi_hclk, nocc_div2_clk,
673*23c8ebc9SAnirudh Srinivasan 			    LSIO_BLK_CG_REG, BIT(0), &refcnt_qspi, 0);
674*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C0_PCLK, lsio_i2c0_pclk, nocc_div4_clk,
675*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(1), 0);
676*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C1_PCLK, lsio_i2c1_pclk, nocc_div4_clk,
677*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(2), 0);
678*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C2_PCLK, lsio_i2c2_pclk, nocc_div4_clk,
679*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(3), 0);
680*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C3_PCLK, lsio_i2c3_pclk, nocc_div4_clk,
681*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(4), 0);
682*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_I2C4_PCLK, lsio_i2c4_pclk, nocc_div4_clk,
683*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(5), 0);
684*23c8ebc9SAnirudh Srinivasan 
685*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART0_PCLK, lsio_uart0_pclk, nocc_div4_clk,
686*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(6), 0);
687*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART1_PCLK, lsio_uart1_pclk, nocc_div4_clk,
688*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(7), 0);
689*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART2_PCLK, lsio_uart2_pclk, nocc_div4_clk,
690*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(8), 0);
691*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART3_PCLK, lsio_uart3_pclk, nocc_div4_clk,
692*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(9), 0);
693*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_UART4_PCLK, lsio_uart4_pclk, nocc_div4_clk,
694*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(10), 0);
695*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SPI0_PCLK, lsio_spi0_pclk, nocc_div4_clk,
696*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(11), 0);
697*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SPI1_PCLK, lsio_spi1_pclk, nocc_div4_clk,
698*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(12), 0);
699*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SPI2_PCLK, lsio_spi2_pclk, nocc_div4_clk,
700*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(13), 0);
701*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_SPI3_PCLK, lsio_spi3_pclk, nocc_div4_clk,
702*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(14), 0);
703*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_DEFINE(CLK_GPIO_PCLK, lsio_gpio_pclk, nocc_div4_clk,
704*23c8ebc9SAnirudh Srinivasan 		     LSIO_BLK_CG_REG, BIT(15), 0);
705*23c8ebc9SAnirudh Srinivasan 
706*23c8ebc9SAnirudh Srinivasan static unsigned int refcnt_can0;
707*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_HCLK, lsio_can0_hclk, nocc_div2_clk,
708*23c8ebc9SAnirudh Srinivasan 			    LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0);
709*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN0_CLK, lsio_can0_clk, nocc_can_clk,
710*23c8ebc9SAnirudh Srinivasan 			    LSIO_BLK_CG_REG, BIT(17), &refcnt_can0, 0);
711*23c8ebc9SAnirudh Srinivasan 
712*23c8ebc9SAnirudh Srinivasan static unsigned int refcnt_can1;
713*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_HCLK, lsio_can1_hclk, nocc_div2_clk,
714*23c8ebc9SAnirudh Srinivasan 			    LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0);
715*23c8ebc9SAnirudh Srinivasan ATLANTIS_GATE_SHARED_DEFINE(CLK_CAN1_CLK, lsio_can1_clk, nocc_can_clk,
716*23c8ebc9SAnirudh Srinivasan 			    LSIO_BLK_CG_REG, BIT(18), &refcnt_can1, 0);
717*23c8ebc9SAnirudh Srinivasan 
718*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_CAN0_TIMER_CLK, lsio_can0_timer_clk,
719*23c8ebc9SAnirudh Srinivasan 				 nocc_rtc_clk, 1, 1, 0);
720*23c8ebc9SAnirudh Srinivasan ATLANTIS_FIXED_FACTOR_DEFINE(CLK_CAN1_TIMER_CLK, lsio_can1_timer_clk,
721*23c8ebc9SAnirudh Srinivasan 				 nocc_rtc_clk, 1, 1, 0);
722*23c8ebc9SAnirudh Srinivasan 
723*23c8ebc9SAnirudh Srinivasan static struct clk_hw *atlantis_rcpu_clks[] = {
724*23c8ebc9SAnirudh Srinivasan 	[CLK_RCPU_PLL]		= &rcpu_pll_clk.common.hw,
725*23c8ebc9SAnirudh Srinivasan 	[CLK_RCPU_ROOT]		= &rcpu_root_clk.common.hw,
726*23c8ebc9SAnirudh Srinivasan 	[CLK_RCPU_DIV2]		= &rcpu_div2_clk.common.hw,
727*23c8ebc9SAnirudh Srinivasan 	[CLK_RCPU_DIV4]		= &rcpu_div4_clk.common.hw,
728*23c8ebc9SAnirudh Srinivasan 	[CLK_RCPU_RTC]		= &rcpu_rtc_clk.common.hw,
729*23c8ebc9SAnirudh Srinivasan 	[CLK_SMNDMA0_ACLK]	= &rcpu_dma0_clk.common.hw,
730*23c8ebc9SAnirudh Srinivasan 	[CLK_SMNDMA1_ACLK]	= &rcpu_dma1_clk.common.hw,
731*23c8ebc9SAnirudh Srinivasan 	[CLK_WDT0_PCLK]		= &sl_wdt0_pclk.common.hw,
732*23c8ebc9SAnirudh Srinivasan 	[CLK_WDT1_PCLK]		= &sl_wdt1_pclk.common.hw,
733*23c8ebc9SAnirudh Srinivasan 	[CLK_TIMER_PCLK]	= &sl_timer_pclk.common.hw,
734*23c8ebc9SAnirudh Srinivasan 	[CLK_PVTC_PCLK]		= &sl_pvtc_pclk.common.hw,
735*23c8ebc9SAnirudh Srinivasan 	[CLK_PMU_PCLK]		= &sl_pmu_pclk.common.hw,
736*23c8ebc9SAnirudh Srinivasan 	[CLK_MAILBOX_HCLK]	= &rcpu_ipc_clk.common.hw,
737*23c8ebc9SAnirudh Srinivasan 	[CLK_SEC_SPACC_HCLK]	= &sec_spacc_hclk.common.hw,
738*23c8ebc9SAnirudh Srinivasan 	[CLK_SEC_OTP_HCLK]	= &sec_otp_hclk.common.hw,
739*23c8ebc9SAnirudh Srinivasan 	[CLK_TRNG_PCLK]		= &sec_trng_pclk.common.hw,
740*23c8ebc9SAnirudh Srinivasan 	[CLK_SEC_CRC_HCLK]	= &sec_crc_hclk.common.hw,
741*23c8ebc9SAnirudh Srinivasan 	[CLK_SMN_HCLK]		= &rcpu_smn_hclk.common.hw,
742*23c8ebc9SAnirudh Srinivasan 	[CLK_AHB0_HCLK]		= &rcpu_ahb0_hclk.common.hw,
743*23c8ebc9SAnirudh Srinivasan 	[CLK_SMN_PCLK]		= &rcpu_smn_pclk.common.hw,
744*23c8ebc9SAnirudh Srinivasan 	[CLK_SMN_CLK]		= &rcpu_smn_clk.common.hw,
745*23c8ebc9SAnirudh Srinivasan 	[CLK_SCRATCHPAD_CLK]	= &rcpu_scratchpad_aclk.common.hw,
746*23c8ebc9SAnirudh Srinivasan 	[CLK_RCPU_CORE_CLK]	= &rcpu_core_clk.common.hw,
747*23c8ebc9SAnirudh Srinivasan 	[CLK_RCPU_ROM_CLK]	= &rcpu_rom_aclk.common.hw,
748*23c8ebc9SAnirudh Srinivasan 	[CLK_OTP_LOAD_CLK]	= &otp_load_clk.common.hw,
749*23c8ebc9SAnirudh Srinivasan 	[CLK_NOC_PLL]		= &nocc_pll_clk.common.hw,
750*23c8ebc9SAnirudh Srinivasan 	[CLK_NOCC_CLK]		= &nocc_clk.common.hw,
751*23c8ebc9SAnirudh Srinivasan 	[CLK_NOCC_DIV2]		= &nocc_div2_clk.common.hw,
752*23c8ebc9SAnirudh Srinivasan 	[CLK_NOCC_DIV4]		= &nocc_div4_clk.common.hw,
753*23c8ebc9SAnirudh Srinivasan 	[CLK_NOCC_RTC]		= &nocc_rtc_clk.common.hw,
754*23c8ebc9SAnirudh Srinivasan 	[CLK_NOCC_CAN]		= &nocc_can_clk.common.hw,
755*23c8ebc9SAnirudh Srinivasan 	[CLK_QSPI_SCLK]		= &lsio_qspi_sclk.common.hw,
756*23c8ebc9SAnirudh Srinivasan 	[CLK_QSPI_HCLK]		= &lsio_qspi_hclk.common.hw,
757*23c8ebc9SAnirudh Srinivasan 	[CLK_I2C0_PCLK]		= &lsio_i2c0_pclk.common.hw,
758*23c8ebc9SAnirudh Srinivasan 	[CLK_I2C1_PCLK]		= &lsio_i2c1_pclk.common.hw,
759*23c8ebc9SAnirudh Srinivasan 	[CLK_I2C2_PCLK]		= &lsio_i2c2_pclk.common.hw,
760*23c8ebc9SAnirudh Srinivasan 	[CLK_I2C3_PCLK]		= &lsio_i2c3_pclk.common.hw,
761*23c8ebc9SAnirudh Srinivasan 	[CLK_I2C4_PCLK]		= &lsio_i2c4_pclk.common.hw,
762*23c8ebc9SAnirudh Srinivasan 	[CLK_UART0_PCLK]	= &lsio_uart0_pclk.common.hw,
763*23c8ebc9SAnirudh Srinivasan 	[CLK_UART1_PCLK]	= &lsio_uart1_pclk.common.hw,
764*23c8ebc9SAnirudh Srinivasan 	[CLK_UART2_PCLK]	= &lsio_uart2_pclk.common.hw,
765*23c8ebc9SAnirudh Srinivasan 	[CLK_UART3_PCLK]	= &lsio_uart3_pclk.common.hw,
766*23c8ebc9SAnirudh Srinivasan 	[CLK_UART4_PCLK]	= &lsio_uart4_pclk.common.hw,
767*23c8ebc9SAnirudh Srinivasan 	[CLK_SPI0_PCLK]		= &lsio_spi0_pclk.common.hw,
768*23c8ebc9SAnirudh Srinivasan 	[CLK_SPI1_PCLK]		= &lsio_spi1_pclk.common.hw,
769*23c8ebc9SAnirudh Srinivasan 	[CLK_SPI2_PCLK]		= &lsio_spi2_pclk.common.hw,
770*23c8ebc9SAnirudh Srinivasan 	[CLK_SPI3_PCLK]		= &lsio_spi3_pclk.common.hw,
771*23c8ebc9SAnirudh Srinivasan 	[CLK_GPIO_PCLK]		= &lsio_gpio_pclk.common.hw,
772*23c8ebc9SAnirudh Srinivasan 	[CLK_CAN0_HCLK]		= &lsio_can0_hclk.common.hw,
773*23c8ebc9SAnirudh Srinivasan 	[CLK_CAN0_CLK]		= &lsio_can0_clk.common.hw,
774*23c8ebc9SAnirudh Srinivasan 	[CLK_CAN1_HCLK]		= &lsio_can1_hclk.common.hw,
775*23c8ebc9SAnirudh Srinivasan 	[CLK_CAN1_CLK]		= &lsio_can1_clk.common.hw,
776*23c8ebc9SAnirudh Srinivasan 	[CLK_CAN0_TIMER_CLK]	= &lsio_can0_timer_clk.common.hw,
777*23c8ebc9SAnirudh Srinivasan 	[CLK_CAN1_TIMER_CLK]	= &lsio_can1_timer_clk.common.hw,
778*23c8ebc9SAnirudh Srinivasan };
779*23c8ebc9SAnirudh Srinivasan 
780*23c8ebc9SAnirudh Srinivasan static const struct atlantis_prcm_data atlantis_prcm_rcpu_data = {
781*23c8ebc9SAnirudh Srinivasan 	.hws = atlantis_rcpu_clks,
782*23c8ebc9SAnirudh Srinivasan 	.num = ARRAY_SIZE(atlantis_rcpu_clks),
783*23c8ebc9SAnirudh Srinivasan 	.reset_name = "rcpu-reset"
784*23c8ebc9SAnirudh Srinivasan };
785*23c8ebc9SAnirudh Srinivasan 
786*23c8ebc9SAnirudh Srinivasan static int atlantis_prcm_clocks_register(struct device *dev,
787*23c8ebc9SAnirudh Srinivasan 					 struct regmap *regmap,
788*23c8ebc9SAnirudh Srinivasan 					 const struct atlantis_prcm_data *data)
789*23c8ebc9SAnirudh Srinivasan {
790*23c8ebc9SAnirudh Srinivasan 	struct clk_hw_onecell_data *clk_data;
791*23c8ebc9SAnirudh Srinivasan 	int i, ret;
792*23c8ebc9SAnirudh Srinivasan 	size_t num_clks = data->num;
793*23c8ebc9SAnirudh Srinivasan 
794*23c8ebc9SAnirudh Srinivasan 	clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, data->num),
795*23c8ebc9SAnirudh Srinivasan 				GFP_KERNEL);
796*23c8ebc9SAnirudh Srinivasan 	if (!clk_data)
797*23c8ebc9SAnirudh Srinivasan 		return -ENOMEM;
798*23c8ebc9SAnirudh Srinivasan 
799*23c8ebc9SAnirudh Srinivasan 	for (i = 0; i < data->num; i++) {
800*23c8ebc9SAnirudh Srinivasan 		struct clk_hw *hw = data->hws[i];
801*23c8ebc9SAnirudh Srinivasan 		struct atlantis_clk_common *common =
802*23c8ebc9SAnirudh Srinivasan 			hw_to_atlantis_clk_common(hw);
803*23c8ebc9SAnirudh Srinivasan 		common->regmap = regmap;
804*23c8ebc9SAnirudh Srinivasan 
805*23c8ebc9SAnirudh Srinivasan 		ret = devm_clk_hw_register(dev, hw);
806*23c8ebc9SAnirudh Srinivasan 		if (ret)
807*23c8ebc9SAnirudh Srinivasan 			return ret;
808*23c8ebc9SAnirudh Srinivasan 
809*23c8ebc9SAnirudh Srinivasan 		clk_data->hws[common->clkid] = hw;
810*23c8ebc9SAnirudh Srinivasan 	}
811*23c8ebc9SAnirudh Srinivasan 
812*23c8ebc9SAnirudh Srinivasan 	clk_data->num = num_clks;
813*23c8ebc9SAnirudh Srinivasan 
814*23c8ebc9SAnirudh Srinivasan 	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
815*23c8ebc9SAnirudh Srinivasan }
816*23c8ebc9SAnirudh Srinivasan 
817*23c8ebc9SAnirudh Srinivasan static int atlantis_prcm_probe(struct platform_device *pdev)
818*23c8ebc9SAnirudh Srinivasan {
819*23c8ebc9SAnirudh Srinivasan 	const struct atlantis_prcm_data *data;
820*23c8ebc9SAnirudh Srinivasan 	struct auxiliary_device *reset_adev;
821*23c8ebc9SAnirudh Srinivasan 	struct regmap *regmap;
822*23c8ebc9SAnirudh Srinivasan 	void __iomem *base;
823*23c8ebc9SAnirudh Srinivasan 	struct device *dev = &pdev->dev;
824*23c8ebc9SAnirudh Srinivasan 	int ret;
825*23c8ebc9SAnirudh Srinivasan 
826*23c8ebc9SAnirudh Srinivasan 	base = devm_platform_ioremap_resource(pdev, 0);
827*23c8ebc9SAnirudh Srinivasan 	if (IS_ERR(base))
828*23c8ebc9SAnirudh Srinivasan 		return dev_err_probe(dev, PTR_ERR(base),
829*23c8ebc9SAnirudh Srinivasan 				     "Failed to map registers\n");
830*23c8ebc9SAnirudh Srinivasan 
831*23c8ebc9SAnirudh Srinivasan 	regmap = devm_regmap_init_mmio(dev, base, &atlantis_prcm_regmap_config);
832*23c8ebc9SAnirudh Srinivasan 	if (IS_ERR(regmap))
833*23c8ebc9SAnirudh Srinivasan 		return dev_err_probe(dev, PTR_ERR(regmap),
834*23c8ebc9SAnirudh Srinivasan 				     "Failed to init regmap\n");
835*23c8ebc9SAnirudh Srinivasan 
836*23c8ebc9SAnirudh Srinivasan 	data = of_device_get_match_data(dev);
837*23c8ebc9SAnirudh Srinivasan 
838*23c8ebc9SAnirudh Srinivasan 	ret = atlantis_prcm_clocks_register(dev, regmap, data);
839*23c8ebc9SAnirudh Srinivasan 	if (ret)
840*23c8ebc9SAnirudh Srinivasan 		return dev_err_probe(dev, ret, "failed to register clocks\n");
841*23c8ebc9SAnirudh Srinivasan 
842*23c8ebc9SAnirudh Srinivasan 	reset_adev = devm_auxiliary_device_create(dev, data->reset_name, NULL);
843*23c8ebc9SAnirudh Srinivasan 	if (!reset_adev)
844*23c8ebc9SAnirudh Srinivasan 		return dev_err_probe(dev, -ENODEV, "failed to register resets\n");
845*23c8ebc9SAnirudh Srinivasan 
846*23c8ebc9SAnirudh Srinivasan 	return 0;
847*23c8ebc9SAnirudh Srinivasan }
848*23c8ebc9SAnirudh Srinivasan 
849*23c8ebc9SAnirudh Srinivasan static const struct of_device_id atlantis_prcm_of_match[] = {
850*23c8ebc9SAnirudh Srinivasan 	{
851*23c8ebc9SAnirudh Srinivasan 		.compatible = "tenstorrent,atlantis-prcm-rcpu",
852*23c8ebc9SAnirudh Srinivasan 		.data = &atlantis_prcm_rcpu_data,
853*23c8ebc9SAnirudh Srinivasan 	},
854*23c8ebc9SAnirudh Srinivasan 	{}
855*23c8ebc9SAnirudh Srinivasan 
856*23c8ebc9SAnirudh Srinivasan };
857*23c8ebc9SAnirudh Srinivasan MODULE_DEVICE_TABLE(of, atlantis_prcm_of_match);
858*23c8ebc9SAnirudh Srinivasan 
859*23c8ebc9SAnirudh Srinivasan static struct platform_driver atlantis_prcm_driver = {
860*23c8ebc9SAnirudh Srinivasan 	.probe = atlantis_prcm_probe,
861*23c8ebc9SAnirudh Srinivasan 	.driver = {
862*23c8ebc9SAnirudh Srinivasan 		.name = "atlantis-prcm",
863*23c8ebc9SAnirudh Srinivasan 		.of_match_table = atlantis_prcm_of_match,
864*23c8ebc9SAnirudh Srinivasan 	},
865*23c8ebc9SAnirudh Srinivasan };
866*23c8ebc9SAnirudh Srinivasan module_platform_driver(atlantis_prcm_driver);
867*23c8ebc9SAnirudh Srinivasan 
868*23c8ebc9SAnirudh Srinivasan MODULE_DESCRIPTION("Tenstorrent Atlantis PRCM Clock Controller Driver");
869*23c8ebc9SAnirudh Srinivasan MODULE_AUTHOR("Anirudh Srinivasan <asrinivasan@oss.tenstorrent.com>");
870*23c8ebc9SAnirudh Srinivasan MODULE_LICENSE("GPL");
871