xref: /openbmc/linux/drivers/clk/x86/clk-cgu.h (revision 106ef3bd)
1d058fd9eSRahul Tanwar /* SPDX-License-Identifier: GPL-2.0 */
2d058fd9eSRahul Tanwar /*
303617731SRahul Tanwar  * Copyright (C) 2020-2022 MaxLinear, Inc.
403617731SRahul Tanwar  * Copyright (C) 2020 Intel Corporation.
503617731SRahul Tanwar  * Zhu Yixin <yzhu@maxlinear.com>
603617731SRahul Tanwar  * Rahul Tanwar <rtanwar@maxlinear.com>
7d058fd9eSRahul Tanwar  */
8d058fd9eSRahul Tanwar 
9d058fd9eSRahul Tanwar #ifndef __CLK_CGU_H
10d058fd9eSRahul Tanwar #define __CLK_CGU_H
11d058fd9eSRahul Tanwar 
1203617731SRahul Tanwar #include <linux/regmap.h>
13d058fd9eSRahul Tanwar 
14d058fd9eSRahul Tanwar struct lgm_clk_mux {
15d058fd9eSRahul Tanwar 	struct clk_hw hw;
1603617731SRahul Tanwar 	struct regmap *membase;
17d058fd9eSRahul Tanwar 	unsigned int reg;
18d058fd9eSRahul Tanwar 	u8 shift;
19d058fd9eSRahul Tanwar 	u8 width;
20d058fd9eSRahul Tanwar 	unsigned long flags;
21d058fd9eSRahul Tanwar };
22d058fd9eSRahul Tanwar 
23d058fd9eSRahul Tanwar struct lgm_clk_divider {
24d058fd9eSRahul Tanwar 	struct clk_hw hw;
2503617731SRahul Tanwar 	struct regmap *membase;
26d058fd9eSRahul Tanwar 	unsigned int reg;
27d058fd9eSRahul Tanwar 	u8 shift;
28d058fd9eSRahul Tanwar 	u8 width;
29d058fd9eSRahul Tanwar 	u8 shift_gate;
30d058fd9eSRahul Tanwar 	u8 width_gate;
31d058fd9eSRahul Tanwar 	unsigned long flags;
32d058fd9eSRahul Tanwar 	const struct clk_div_table *table;
33d058fd9eSRahul Tanwar };
34d058fd9eSRahul Tanwar 
35d058fd9eSRahul Tanwar struct lgm_clk_ddiv {
36d058fd9eSRahul Tanwar 	struct clk_hw hw;
3703617731SRahul Tanwar 	struct regmap *membase;
38d058fd9eSRahul Tanwar 	unsigned int reg;
39d058fd9eSRahul Tanwar 	u8 shift0;
40d058fd9eSRahul Tanwar 	u8 width0;
41d058fd9eSRahul Tanwar 	u8 shift1;
42d058fd9eSRahul Tanwar 	u8 width1;
43d058fd9eSRahul Tanwar 	u8 shift2;
44d058fd9eSRahul Tanwar 	u8 width2;
45d058fd9eSRahul Tanwar 	u8 shift_gate;
46d058fd9eSRahul Tanwar 	u8 width_gate;
47d058fd9eSRahul Tanwar 	unsigned int mult;
48d058fd9eSRahul Tanwar 	unsigned int div;
49d058fd9eSRahul Tanwar 	unsigned long flags;
50d058fd9eSRahul Tanwar };
51d058fd9eSRahul Tanwar 
52d058fd9eSRahul Tanwar struct lgm_clk_gate {
53d058fd9eSRahul Tanwar 	struct clk_hw hw;
5403617731SRahul Tanwar 	struct regmap *membase;
55d058fd9eSRahul Tanwar 	unsigned int reg;
56d058fd9eSRahul Tanwar 	u8 shift;
57d058fd9eSRahul Tanwar 	unsigned long flags;
58d058fd9eSRahul Tanwar };
59d058fd9eSRahul Tanwar 
60d058fd9eSRahul Tanwar enum lgm_clk_type {
61d058fd9eSRahul Tanwar 	CLK_TYPE_FIXED,
62d058fd9eSRahul Tanwar 	CLK_TYPE_MUX,
63d058fd9eSRahul Tanwar 	CLK_TYPE_DIVIDER,
64d058fd9eSRahul Tanwar 	CLK_TYPE_FIXED_FACTOR,
65d058fd9eSRahul Tanwar 	CLK_TYPE_GATE,
66d058fd9eSRahul Tanwar 	CLK_TYPE_NONE,
67d058fd9eSRahul Tanwar };
68d058fd9eSRahul Tanwar 
69d058fd9eSRahul Tanwar /**
70d058fd9eSRahul Tanwar  * struct lgm_clk_provider
71d058fd9eSRahul Tanwar  * @membase: IO mem base address for CGU.
72d058fd9eSRahul Tanwar  * @np: device node
73d058fd9eSRahul Tanwar  * @dev: device
74d058fd9eSRahul Tanwar  * @clk_data: array of hw clocks and clk number.
75d058fd9eSRahul Tanwar  */
76d058fd9eSRahul Tanwar struct lgm_clk_provider {
7703617731SRahul Tanwar 	struct regmap *membase;
78d058fd9eSRahul Tanwar 	struct device_node *np;
79d058fd9eSRahul Tanwar 	struct device *dev;
80d058fd9eSRahul Tanwar 	struct clk_hw_onecell_data clk_data;
81d058fd9eSRahul Tanwar };
82d058fd9eSRahul Tanwar 
83d058fd9eSRahul Tanwar enum pll_type {
84d058fd9eSRahul Tanwar 	TYPE_ROPLL,
85d058fd9eSRahul Tanwar 	TYPE_LJPLL,
86d058fd9eSRahul Tanwar 	TYPE_NONE,
87d058fd9eSRahul Tanwar };
88d058fd9eSRahul Tanwar 
89d058fd9eSRahul Tanwar struct lgm_clk_pll {
90d058fd9eSRahul Tanwar 	struct clk_hw hw;
9103617731SRahul Tanwar 	struct regmap *membase;
92d058fd9eSRahul Tanwar 	unsigned int reg;
93d058fd9eSRahul Tanwar 	unsigned long flags;
94d058fd9eSRahul Tanwar 	enum pll_type type;
95d058fd9eSRahul Tanwar };
96d058fd9eSRahul Tanwar 
97d058fd9eSRahul Tanwar /**
98d058fd9eSRahul Tanwar  * struct lgm_pll_clk_data
99d058fd9eSRahul Tanwar  * @id: platform specific id of the clock.
100d058fd9eSRahul Tanwar  * @name: name of this pll clock.
101d058fd9eSRahul Tanwar  * @parent_data: parent clock data.
102d058fd9eSRahul Tanwar  * @num_parents: number of parents.
103d058fd9eSRahul Tanwar  * @flags: optional flags for basic clock.
104d058fd9eSRahul Tanwar  * @type: platform type of pll.
105d058fd9eSRahul Tanwar  * @reg: offset of the register.
106d058fd9eSRahul Tanwar  */
107d058fd9eSRahul Tanwar struct lgm_pll_clk_data {
108d058fd9eSRahul Tanwar 	unsigned int id;
109d058fd9eSRahul Tanwar 	const char *name;
110d058fd9eSRahul Tanwar 	const struct clk_parent_data *parent_data;
111d058fd9eSRahul Tanwar 	u8 num_parents;
112d058fd9eSRahul Tanwar 	unsigned long flags;
113d058fd9eSRahul Tanwar 	enum pll_type type;
114d058fd9eSRahul Tanwar 	int reg;
115d058fd9eSRahul Tanwar };
116d058fd9eSRahul Tanwar 
117d058fd9eSRahul Tanwar #define LGM_PLL(_id, _name, _pdata, _flags,		\
118d058fd9eSRahul Tanwar 		_reg, _type)				\
119d058fd9eSRahul Tanwar 	{						\
120d058fd9eSRahul Tanwar 		.id = _id,				\
121d058fd9eSRahul Tanwar 		.name = _name,				\
122d058fd9eSRahul Tanwar 		.parent_data = _pdata,			\
123d058fd9eSRahul Tanwar 		.num_parents = ARRAY_SIZE(_pdata),	\
124d058fd9eSRahul Tanwar 		.flags = _flags,			\
125d058fd9eSRahul Tanwar 		.reg = _reg,				\
126d058fd9eSRahul Tanwar 		.type = _type,				\
127d058fd9eSRahul Tanwar 	}
128d058fd9eSRahul Tanwar 
129d058fd9eSRahul Tanwar struct lgm_clk_ddiv_data {
130d058fd9eSRahul Tanwar 	unsigned int id;
131d058fd9eSRahul Tanwar 	const char *name;
132d058fd9eSRahul Tanwar 	const struct clk_parent_data *parent_data;
133d058fd9eSRahul Tanwar 	u8 flags;
134d058fd9eSRahul Tanwar 	unsigned long div_flags;
135d058fd9eSRahul Tanwar 	unsigned int reg;
136d058fd9eSRahul Tanwar 	u8 shift0;
137d058fd9eSRahul Tanwar 	u8 width0;
138d058fd9eSRahul Tanwar 	u8 shift1;
139d058fd9eSRahul Tanwar 	u8 width1;
140d058fd9eSRahul Tanwar 	u8 shift_gate;
141d058fd9eSRahul Tanwar 	u8 width_gate;
142d058fd9eSRahul Tanwar 	u8 ex_shift;
143d058fd9eSRahul Tanwar 	u8 ex_width;
144d058fd9eSRahul Tanwar };
145d058fd9eSRahul Tanwar 
146d058fd9eSRahul Tanwar #define LGM_DDIV(_id, _name, _pname, _flags, _reg,		\
147d058fd9eSRahul Tanwar 		 _shft0, _wdth0, _shft1, _wdth1,		\
148d058fd9eSRahul Tanwar 		 _shft_gate, _wdth_gate, _xshft, _df)		\
149d058fd9eSRahul Tanwar 	{							\
150d058fd9eSRahul Tanwar 		.id = _id,					\
151d058fd9eSRahul Tanwar 		.name = _name,					\
152d058fd9eSRahul Tanwar 		.parent_data = &(const struct clk_parent_data){	\
153d058fd9eSRahul Tanwar 			.fw_name = _pname,			\
154d058fd9eSRahul Tanwar 			.name = _pname,				\
155d058fd9eSRahul Tanwar 		},						\
156d058fd9eSRahul Tanwar 		.flags = _flags,				\
157d058fd9eSRahul Tanwar 		.reg = _reg,					\
158d058fd9eSRahul Tanwar 		.shift0 = _shft0,				\
159d058fd9eSRahul Tanwar 		.width0 = _wdth0,				\
160d058fd9eSRahul Tanwar 		.shift1 = _shft1,				\
161d058fd9eSRahul Tanwar 		.width1 = _wdth1,				\
162d058fd9eSRahul Tanwar 		.shift_gate = _shft_gate,			\
163d058fd9eSRahul Tanwar 		.width_gate = _wdth_gate,			\
164d058fd9eSRahul Tanwar 		.ex_shift = _xshft,				\
165d058fd9eSRahul Tanwar 		.ex_width = 1,					\
166d058fd9eSRahul Tanwar 		.div_flags = _df,				\
167d058fd9eSRahul Tanwar 	}
168d058fd9eSRahul Tanwar 
169d058fd9eSRahul Tanwar struct lgm_clk_branch {
170d058fd9eSRahul Tanwar 	unsigned int id;
171d058fd9eSRahul Tanwar 	enum lgm_clk_type type;
172d058fd9eSRahul Tanwar 	const char *name;
173d058fd9eSRahul Tanwar 	const struct clk_parent_data *parent_data;
174d058fd9eSRahul Tanwar 	u8 num_parents;
175d058fd9eSRahul Tanwar 	unsigned long flags;
176d058fd9eSRahul Tanwar 	unsigned int mux_off;
177d058fd9eSRahul Tanwar 	u8 mux_shift;
178d058fd9eSRahul Tanwar 	u8 mux_width;
179d058fd9eSRahul Tanwar 	unsigned long mux_flags;
180d058fd9eSRahul Tanwar 	unsigned int mux_val;
181d058fd9eSRahul Tanwar 	unsigned int div_off;
182d058fd9eSRahul Tanwar 	u8 div_shift;
183d058fd9eSRahul Tanwar 	u8 div_width;
184d058fd9eSRahul Tanwar 	u8 div_shift_gate;
185d058fd9eSRahul Tanwar 	u8 div_width_gate;
186d058fd9eSRahul Tanwar 	unsigned long div_flags;
187d058fd9eSRahul Tanwar 	unsigned int div_val;
188d058fd9eSRahul Tanwar 	const struct clk_div_table *div_table;
189d058fd9eSRahul Tanwar 	unsigned int gate_off;
190d058fd9eSRahul Tanwar 	u8 gate_shift;
191d058fd9eSRahul Tanwar 	unsigned long gate_flags;
192d058fd9eSRahul Tanwar 	unsigned int gate_val;
193d058fd9eSRahul Tanwar 	unsigned int mult;
194d058fd9eSRahul Tanwar 	unsigned int div;
195d058fd9eSRahul Tanwar };
196d058fd9eSRahul Tanwar 
197d058fd9eSRahul Tanwar /* clock flags definition */
198d058fd9eSRahul Tanwar #define CLOCK_FLAG_VAL_INIT	BIT(16)
199d058fd9eSRahul Tanwar #define MUX_CLK_SW		BIT(17)
200a5d49bd3SRahul Tanwar #define GATE_CLK_HW		BIT(18)
201*106ef3bdSRahul Tanwar #define DIV_CLK_NO_MASK		BIT(19)
202d058fd9eSRahul Tanwar 
203d058fd9eSRahul Tanwar #define LGM_MUX(_id, _name, _pdata, _f, _reg,		\
204d058fd9eSRahul Tanwar 		_shift, _width, _cf, _v)		\
205d058fd9eSRahul Tanwar 	{						\
206d058fd9eSRahul Tanwar 		.id = _id,				\
207d058fd9eSRahul Tanwar 		.type = CLK_TYPE_MUX,			\
208d058fd9eSRahul Tanwar 		.name = _name,				\
209d058fd9eSRahul Tanwar 		.parent_data = _pdata,			\
210d058fd9eSRahul Tanwar 		.num_parents = ARRAY_SIZE(_pdata),	\
211d058fd9eSRahul Tanwar 		.flags = _f,				\
212d058fd9eSRahul Tanwar 		.mux_off = _reg,			\
213d058fd9eSRahul Tanwar 		.mux_shift = _shift,			\
214d058fd9eSRahul Tanwar 		.mux_width = _width,			\
215d058fd9eSRahul Tanwar 		.mux_flags = _cf,			\
216d058fd9eSRahul Tanwar 		.mux_val = _v,				\
217d058fd9eSRahul Tanwar 	}
218d058fd9eSRahul Tanwar 
219d058fd9eSRahul Tanwar #define LGM_DIV(_id, _name, _pname, _f, _reg, _shift, _width,	\
220d058fd9eSRahul Tanwar 		_shift_gate, _width_gate, _cf, _v, _dtable)	\
221d058fd9eSRahul Tanwar 	{							\
222d058fd9eSRahul Tanwar 		.id = _id,					\
223d058fd9eSRahul Tanwar 		.type = CLK_TYPE_DIVIDER,			\
224d058fd9eSRahul Tanwar 		.name = _name,					\
225d058fd9eSRahul Tanwar 		.parent_data = &(const struct clk_parent_data){	\
226d058fd9eSRahul Tanwar 			.fw_name = _pname,			\
227d058fd9eSRahul Tanwar 			.name = _pname,				\
228d058fd9eSRahul Tanwar 		},						\
229d058fd9eSRahul Tanwar 		.num_parents = 1,				\
230d058fd9eSRahul Tanwar 		.flags = _f,					\
231d058fd9eSRahul Tanwar 		.div_off = _reg,				\
232d058fd9eSRahul Tanwar 		.div_shift = _shift,				\
233d058fd9eSRahul Tanwar 		.div_width = _width,				\
234d058fd9eSRahul Tanwar 		.div_shift_gate = _shift_gate,			\
235d058fd9eSRahul Tanwar 		.div_width_gate = _width_gate,			\
236d058fd9eSRahul Tanwar 		.div_flags = _cf,				\
237d058fd9eSRahul Tanwar 		.div_val = _v,					\
238d058fd9eSRahul Tanwar 		.div_table = _dtable,				\
239d058fd9eSRahul Tanwar 	}
240d058fd9eSRahul Tanwar 
241d058fd9eSRahul Tanwar #define LGM_GATE(_id, _name, _pname, _f, _reg,			\
242d058fd9eSRahul Tanwar 		 _shift, _cf, _v)				\
243d058fd9eSRahul Tanwar 	{							\
244d058fd9eSRahul Tanwar 		.id = _id,					\
245d058fd9eSRahul Tanwar 		.type = CLK_TYPE_GATE,				\
246d058fd9eSRahul Tanwar 		.name = _name,					\
247d058fd9eSRahul Tanwar 		.parent_data = &(const struct clk_parent_data){	\
248d058fd9eSRahul Tanwar 			.fw_name = _pname,			\
249d058fd9eSRahul Tanwar 			.name = _pname,				\
250d058fd9eSRahul Tanwar 		},						\
251d058fd9eSRahul Tanwar 		.num_parents = !_pname ? 0 : 1,			\
252d058fd9eSRahul Tanwar 		.flags = _f,					\
253d058fd9eSRahul Tanwar 		.gate_off = _reg,				\
254d058fd9eSRahul Tanwar 		.gate_shift = _shift,				\
255d058fd9eSRahul Tanwar 		.gate_flags = _cf,				\
256d058fd9eSRahul Tanwar 		.gate_val = _v,					\
257d058fd9eSRahul Tanwar 	}
258d058fd9eSRahul Tanwar 
259d058fd9eSRahul Tanwar #define LGM_FIXED(_id, _name, _pname, _f, _reg,			\
260d058fd9eSRahul Tanwar 		  _shift, _width, _cf, _freq, _v)		\
261d058fd9eSRahul Tanwar 	{							\
262d058fd9eSRahul Tanwar 		.id = _id,					\
263d058fd9eSRahul Tanwar 		.type = CLK_TYPE_FIXED,				\
264d058fd9eSRahul Tanwar 		.name = _name,					\
265d058fd9eSRahul Tanwar 		.parent_data = &(const struct clk_parent_data){	\
266d058fd9eSRahul Tanwar 			.fw_name = _pname,			\
267d058fd9eSRahul Tanwar 			.name = _pname,				\
268d058fd9eSRahul Tanwar 		},						\
269d058fd9eSRahul Tanwar 		.num_parents = !_pname ? 0 : 1,			\
270d058fd9eSRahul Tanwar 		.flags = _f,					\
271d058fd9eSRahul Tanwar 		.div_off = _reg,				\
272d058fd9eSRahul Tanwar 		.div_shift = _shift,				\
273d058fd9eSRahul Tanwar 		.div_width = _width,				\
274d058fd9eSRahul Tanwar 		.div_flags = _cf,				\
275d058fd9eSRahul Tanwar 		.div_val = _v,					\
276d058fd9eSRahul Tanwar 		.mux_flags = _freq,				\
277d058fd9eSRahul Tanwar 	}
278d058fd9eSRahul Tanwar 
279d058fd9eSRahul Tanwar #define LGM_FIXED_FACTOR(_id, _name, _pname, _f, _reg,		\
280d058fd9eSRahul Tanwar 			 _shift, _width, _cf, _v, _m, _d)	\
281d058fd9eSRahul Tanwar 	{							\
282d058fd9eSRahul Tanwar 		.id = _id,					\
283d058fd9eSRahul Tanwar 		.type = CLK_TYPE_FIXED_FACTOR,			\
284d058fd9eSRahul Tanwar 		.name = _name,					\
285d058fd9eSRahul Tanwar 		.parent_data = &(const struct clk_parent_data){	\
286d058fd9eSRahul Tanwar 			.fw_name = _pname,			\
287d058fd9eSRahul Tanwar 			.name = _pname,				\
288d058fd9eSRahul Tanwar 		},						\
289d058fd9eSRahul Tanwar 		.num_parents = 1,				\
290d058fd9eSRahul Tanwar 		.flags = _f,					\
291d058fd9eSRahul Tanwar 		.div_off = _reg,				\
292d058fd9eSRahul Tanwar 		.div_shift = _shift,				\
293d058fd9eSRahul Tanwar 		.div_width = _width,				\
294d058fd9eSRahul Tanwar 		.div_flags = _cf,				\
295d058fd9eSRahul Tanwar 		.div_val = _v,					\
296d058fd9eSRahul Tanwar 		.mult = _m,					\
297d058fd9eSRahul Tanwar 		.div = _d,					\
298d058fd9eSRahul Tanwar 	}
299d058fd9eSRahul Tanwar 
lgm_set_clk_val(struct regmap * membase,u32 reg,u8 shift,u8 width,u32 set_val)30003617731SRahul Tanwar static inline void lgm_set_clk_val(struct regmap *membase, u32 reg,
301d058fd9eSRahul Tanwar 				   u8 shift, u8 width, u32 set_val)
302d058fd9eSRahul Tanwar {
303d058fd9eSRahul Tanwar 	u32 mask = (GENMASK(width - 1, 0) << shift);
304d058fd9eSRahul Tanwar 
30503617731SRahul Tanwar 	regmap_update_bits(membase, reg, mask, set_val << shift);
306d058fd9eSRahul Tanwar }
307d058fd9eSRahul Tanwar 
lgm_get_clk_val(struct regmap * membase,u32 reg,u8 shift,u8 width)30803617731SRahul Tanwar static inline u32 lgm_get_clk_val(struct regmap *membase, u32 reg,
309d058fd9eSRahul Tanwar 				  u8 shift, u8 width)
310d058fd9eSRahul Tanwar {
311d058fd9eSRahul Tanwar 	u32 mask = (GENMASK(width - 1, 0) << shift);
312d058fd9eSRahul Tanwar 	u32 val;
313d058fd9eSRahul Tanwar 
31403617731SRahul Tanwar 	if (regmap_read(membase, reg, &val)) {
31503617731SRahul Tanwar 		WARN_ONCE(1, "Failed to read clk reg: 0x%x\n", reg);
31603617731SRahul Tanwar 		return 0;
31703617731SRahul Tanwar 	}
31803617731SRahul Tanwar 
319d058fd9eSRahul Tanwar 	val = (val & mask) >> shift;
320d058fd9eSRahul Tanwar 
321d058fd9eSRahul Tanwar 	return val;
322d058fd9eSRahul Tanwar }
323d058fd9eSRahul Tanwar 
32403617731SRahul Tanwar 
32503617731SRahul Tanwar 
326d058fd9eSRahul Tanwar int lgm_clk_register_branches(struct lgm_clk_provider *ctx,
327d058fd9eSRahul Tanwar 			      const struct lgm_clk_branch *list,
328d058fd9eSRahul Tanwar 			      unsigned int nr_clk);
329d058fd9eSRahul Tanwar int lgm_clk_register_plls(struct lgm_clk_provider *ctx,
330d058fd9eSRahul Tanwar 			  const struct lgm_pll_clk_data *list,
331d058fd9eSRahul Tanwar 			  unsigned int nr_clk);
332d058fd9eSRahul Tanwar int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx,
333d058fd9eSRahul Tanwar 			  const struct lgm_clk_ddiv_data *list,
334d058fd9eSRahul Tanwar 			  unsigned int nr_clk);
335d058fd9eSRahul Tanwar #endif	/* __CLK_CGU_H */
336