xref: /linux/drivers/clk/ultrarisc/clk-ultrarisc.c (revision 502d45774af09f1c681c754c4b7cdfb5d7f72fd9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
4  */
5 
6 #include <linux/bitfield.h>
7 #include <linux/clk-provider.h>
8 #include <linux/io.h>
9 #include <linux/math64.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 
13 #include "clk-ultrarisc.h"
14 
15 struct ultrarisc_pll_clk {
16 	struct clk_hw hw;
17 	void __iomem *base;
18 	const struct ultrarisc_pll_layout *layout;
19 };
20 
21 struct ultrarisc_divider_clk {
22 	struct clk_divider divider;
23 	struct clk_gate gate;
24 	u32 load_mask;
25 };
26 
27 #define to_ultrarisc_pll_clk(_hw) \
28 	container_of(_hw, struct ultrarisc_pll_clk, hw)
29 
to_ultrarisc_divider_clk(struct clk_hw * hw)30 static inline struct ultrarisc_divider_clk *to_ultrarisc_divider_clk(struct clk_hw *hw)
31 {
32 	struct clk_divider *divider = to_clk_divider(hw);
33 
34 	return container_of(divider, struct ultrarisc_divider_clk, divider);
35 }
36 
ultrarisc_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)37 static unsigned long ultrarisc_pll_recalc_rate(struct clk_hw *hw,
38 					       unsigned long parent_rate)
39 {
40 	struct ultrarisc_pll_clk *pll = to_ultrarisc_pll_clk(hw);
41 	const struct ultrarisc_pll_layout *layout = pll->layout;
42 	u32 oddiv1_div, oddiv2_div;
43 	u64 mult, rate, den;
44 	u32 frac, m, n;
45 	u32 cfg1, cfg2;
46 
47 	cfg1 = readl_relaxed(pll->base + layout->cfg1_offset);
48 	cfg2 = readl_relaxed(pll->base + layout->cfg2_offset);
49 
50 	frac = field_get(layout->frac_mask, cfg1);
51 	m = field_get(layout->m_mask, cfg2);
52 	n = field_get(layout->n_mask, cfg2);
53 	if (!n)
54 		return 0;
55 
56 	oddiv1_div = 1U << field_get(layout->oddiv1_mask, cfg2);
57 	oddiv2_div = 1U << field_get(layout->oddiv2_mask, cfg2);
58 
59 	/*
60 	 * The output frequency is calculated as:
61 	 * fvco = parent * (m + frac / 2^24) / n
62 	 * fout = fvco / (2^oddiv1_raw * 2^oddiv2_raw)
63 	 *
64 	 * The output divider values are derived from the raw register field values as:
65 	 * oddivX_div = 1 << oddivX_raw
66 	 */
67 	mult = ((u64)m << 24) + frac;
68 	rate = (u64)parent_rate * mult;
69 	den = ((u64)n << 24) * oddiv1_div * oddiv2_div;
70 
71 	return div64_u64(rate + (den >> 1), den);
72 }
73 
74 static const struct clk_ops ultrarisc_pll_ro_ops = {
75 	.recalc_rate = ultrarisc_pll_recalc_rate,
76 };
77 
ultrarisc_divider_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)78 static unsigned long ultrarisc_divider_recalc_rate(struct clk_hw *hw,
79 						   unsigned long parent_rate)
80 {
81 	struct clk_divider *divider = to_clk_divider(hw);
82 	u32 val;
83 
84 	val = readl_relaxed(divider->reg) >> divider->shift;
85 	val &= clk_div_mask(divider->width);
86 
87 	return divider_recalc_rate(hw, parent_rate, val, divider->table,
88 				   divider->flags, divider->width);
89 }
90 
ultrarisc_divider_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)91 static int ultrarisc_divider_determine_rate(struct clk_hw *hw,
92 					    struct clk_rate_request *req)
93 {
94 	struct clk_divider *divider = to_clk_divider(hw);
95 
96 	return divider_determine_rate(hw, req, divider->table, divider->width,
97 				      divider->flags);
98 }
99 
ultrarisc_divider_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)100 static int ultrarisc_divider_set_rate(struct clk_hw *hw, unsigned long rate,
101 				      unsigned long parent_rate)
102 {
103 	struct ultrarisc_divider_clk *divider_clk = to_ultrarisc_divider_clk(hw);
104 	struct clk_divider *divider = &divider_clk->divider;
105 	int value;
106 	u32 val;
107 
108 	value = divider_get_val(rate, parent_rate, divider->table,
109 				divider->width, divider->flags);
110 	if (value < 0)
111 		return value;
112 
113 	scoped_guard(spinlock_irqsave, divider->lock) {
114 		val = readl_relaxed(divider->reg);
115 		val &= ~(clk_div_mask(divider->width) << divider->shift);
116 		val |= value << divider->shift;
117 		writel_relaxed(val, divider->reg);
118 
119 		if (divider_clk->load_mask) {
120 			/*
121 			 * Program the new divider field, then write 1 to the
122 			 * load bit to trigger the update. The load bit is
123 			 * write-triggered and reads back as 0 on this hardware.
124 			 */
125 			writel_relaxed(val | divider_clk->load_mask, divider->reg);
126 		}
127 	}
128 
129 	return 0;
130 }
131 
132 static const struct clk_ops ultrarisc_divider_ops = {
133 	.recalc_rate = ultrarisc_divider_recalc_rate,
134 	.determine_rate = ultrarisc_divider_determine_rate,
135 	.set_rate = ultrarisc_divider_set_rate,
136 };
137 
ultrarisc_clk_register_pll(struct device * dev,const struct ultrarisc_pll_desc * desc,const struct ultrarisc_pll_layout * layout,void __iomem * base)138 static struct clk_hw *ultrarisc_clk_register_pll(struct device *dev,
139 						 const struct ultrarisc_pll_desc *desc,
140 						 const struct ultrarisc_pll_layout *layout,
141 						 void __iomem *base)
142 {
143 	struct clk_parent_data pdata = { .index = 0 };
144 	struct ultrarisc_pll_clk *pll;
145 	struct clk_init_data init = {
146 		.name = desc->name,
147 		.ops = &ultrarisc_pll_ro_ops,
148 		.parent_data = &pdata,
149 		.num_parents = 1,
150 		.flags = CLK_GET_RATE_NOCACHE,
151 	};
152 	int ret;
153 
154 	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
155 	if (!pll)
156 		return ERR_PTR(-ENOMEM);
157 
158 	pll->base = base;
159 	pll->layout = layout;
160 	pll->hw.init = &init;
161 
162 	ret = devm_clk_hw_register(dev, &pll->hw);
163 	if (ret)
164 		return ERR_PTR(ret);
165 
166 	return &pll->hw;
167 }
168 
169 static struct clk_hw *
ultrarisc_clk_register_divider(struct device * dev,const struct ultrarisc_divider_desc * desc,struct clk_hw * parent_hw,void __iomem * base,spinlock_t * lock)170 ultrarisc_clk_register_divider(struct device *dev,
171 			       const struct ultrarisc_divider_desc *desc,
172 			       struct clk_hw *parent_hw, void __iomem *base,
173 			       spinlock_t *lock)
174 {
175 	const struct clk_parent_data pdata = { .hw = parent_hw };
176 	void __iomem *reg = base + desc->offset;
177 	struct ultrarisc_divider_clk *divider;
178 
179 	if (!desc->div_width)
180 		return ERR_PTR(-EINVAL);
181 
182 	if (!lock)
183 		return ERR_PTR(-EINVAL);
184 
185 	divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
186 	if (!divider)
187 		return ERR_PTR(-ENOMEM);
188 
189 	divider->divider.reg = reg;
190 	divider->divider.shift = desc->div_shift;
191 	divider->divider.width = desc->div_width;
192 	divider->divider.flags = desc->divider_flags;
193 	divider->divider.lock = lock;
194 	divider->load_mask = desc->load_mask;
195 	divider->gate.reg = reg;
196 	divider->gate.bit_idx = desc->gate_bit;
197 	divider->gate.flags = desc->gate_flags;
198 	divider->gate.lock = lock;
199 
200 	return devm_clk_hw_register_composite_pdata(dev, desc->name,
201 						    &pdata, 1, NULL, NULL,
202 						    &divider->divider.hw,
203 						    &ultrarisc_divider_ops,
204 						    &divider->gate.hw,
205 						    &clk_gate_ops, 0);
206 }
207 
ultrarisc_clk_register_fixed_factors(struct device * dev,struct clk_hw_onecell_data * clk_data,const struct ultrarisc_clk_soc_data * soc_data)208 static int ultrarisc_clk_register_fixed_factors(struct device *dev,
209 						struct clk_hw_onecell_data *clk_data,
210 						const struct ultrarisc_clk_soc_data *soc_data)
211 {
212 	u32 i;
213 
214 	for (i = 0; i < soc_data->num_fixed_factors; i++) {
215 		const struct ultrarisc_fixed_factor_desc *desc;
216 		struct clk_hw *parent_hw;
217 		struct clk_hw *hw;
218 
219 		desc = &soc_data->fixed_factors[i];
220 		if (desc->id >= clk_data->num || desc->parent_id >= clk_data->num)
221 			return -EINVAL;
222 
223 		parent_hw = clk_data->hws[desc->parent_id];
224 		if (!parent_hw)
225 			return -EINVAL;
226 
227 		hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, desc->name,
228 								 parent_hw, 0,
229 								 desc->mult,
230 								 desc->div);
231 		if (IS_ERR(hw))
232 			return PTR_ERR(hw);
233 
234 		clk_data->hws[desc->id] = hw;
235 	}
236 
237 	return 0;
238 }
239 
ultrarisc_clk_register_plls(struct platform_device * pdev,struct clk_hw_onecell_data * clk_data,const struct ultrarisc_clk_soc_data * soc_data,void __iomem * base)240 static int ultrarisc_clk_register_plls(struct platform_device *pdev,
241 				       struct clk_hw_onecell_data *clk_data,
242 				       const struct ultrarisc_clk_soc_data *soc_data,
243 				       void __iomem *base)
244 {
245 	struct device *dev = &pdev->dev;
246 	u32 i;
247 
248 	for (i = 0; i < soc_data->num_plls; i++) {
249 		const struct ultrarisc_pll_desc *desc = &soc_data->plls[i];
250 		struct clk_hw *hw;
251 
252 		if (desc->id >= clk_data->num) {
253 			dev_err(dev, "%s invalid clock ID %u >= %u\n",
254 				desc->name, desc->id, clk_data->num);
255 			return -EINVAL;
256 		}
257 
258 		hw = ultrarisc_clk_register_pll(dev, desc, soc_data->pll_layout, base);
259 		if (IS_ERR(hw))
260 			return PTR_ERR(hw);
261 
262 		clk_data->hws[desc->id] = hw;
263 	}
264 
265 	return 0;
266 }
267 
ultrarisc_clk_register_dividers(struct platform_device * pdev,struct clk_hw_onecell_data * clk_data,const struct ultrarisc_clk_soc_data * soc_data,void __iomem * base,spinlock_t * lock)268 static int ultrarisc_clk_register_dividers(struct platform_device *pdev,
269 					   struct clk_hw_onecell_data *clk_data,
270 					   const struct ultrarisc_clk_soc_data *soc_data,
271 					   void __iomem *base,
272 					   spinlock_t *lock)
273 {
274 	struct device *dev = &pdev->dev;
275 	u32 i;
276 
277 	for (i = 0; i < soc_data->num_dividers; i++) {
278 		const struct ultrarisc_divider_desc *desc;
279 		struct clk_hw *parent_hw;
280 		struct clk_hw *hw;
281 
282 		desc = &soc_data->dividers[i];
283 		if (desc->id >= clk_data->num || desc->parent_id >= clk_data->num)
284 			return -EINVAL;
285 
286 		parent_hw = clk_data->hws[desc->parent_id];
287 		if (!parent_hw)
288 			return -EINVAL;
289 
290 		hw = ultrarisc_clk_register_divider(dev, desc, parent_hw, base,
291 						    lock);
292 		if (IS_ERR(hw))
293 			return PTR_ERR(hw);
294 
295 		if (desc->max_rate)
296 			clk_hw_set_rate_range(hw, 0, desc->max_rate);
297 
298 		clk_data->hws[desc->id] = hw;
299 	}
300 
301 	return 0;
302 }
303 
ultrarisc_clk_register_gates(struct platform_device * pdev,struct clk_hw_onecell_data * clk_data,const struct ultrarisc_clk_soc_data * soc_data,void __iomem * base,spinlock_t * lock)304 static int ultrarisc_clk_register_gates(struct platform_device *pdev,
305 					struct clk_hw_onecell_data *clk_data,
306 					const struct ultrarisc_clk_soc_data *soc_data,
307 					void __iomem *base,
308 					spinlock_t *lock)
309 {
310 	struct device *dev = &pdev->dev;
311 	u32 i;
312 
313 	for (i = 0; i < soc_data->num_gates; i++) {
314 		const struct ultrarisc_gate_desc *desc;
315 		struct clk_hw *parent_hw;
316 		struct clk_hw *hw;
317 
318 		desc = &soc_data->gates[i];
319 		if (desc->id >= clk_data->num || desc->parent_id >= clk_data->num)
320 			return -EINVAL;
321 
322 		parent_hw = clk_data->hws[desc->parent_id];
323 		if (!parent_hw)
324 			return -EINVAL;
325 
326 		hw = devm_clk_hw_register_gate_parent_hw(dev, desc->name,
327 							 parent_hw, 0,
328 							 base + desc->offset,
329 							 desc->gate_bit,
330 							 desc->gate_flags,
331 							 lock);
332 		if (IS_ERR(hw))
333 			return PTR_ERR(hw);
334 
335 		clk_data->hws[desc->id] = hw;
336 	}
337 
338 	return 0;
339 }
340 
ultrarisc_clk_probe(struct platform_device * pdev,const struct ultrarisc_clk_soc_data * soc_data)341 int ultrarisc_clk_probe(struct platform_device *pdev,
342 			const struct ultrarisc_clk_soc_data *soc_data)
343 {
344 	struct clk_hw_onecell_data *clk_data;
345 	struct device *dev = &pdev->dev;
346 	void __iomem *base;
347 	spinlock_t *lock;
348 	int ret;
349 
350 	if (!soc_data)
351 		return -EINVAL;
352 
353 	lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
354 	if (!lock)
355 		return -ENOMEM;
356 
357 	spin_lock_init(lock);
358 
359 	clk_data = devm_kzalloc(dev, struct_size(clk_data, hws,
360 						 soc_data->num_clks),
361 				GFP_KERNEL);
362 	if (!clk_data)
363 		return -ENOMEM;
364 
365 	clk_data->num = soc_data->num_clks;
366 
367 	base = devm_platform_ioremap_resource(pdev, 0);
368 	if (IS_ERR(base))
369 		return PTR_ERR(base);
370 
371 	ret = ultrarisc_clk_register_plls(pdev, clk_data, soc_data, base);
372 	if (ret)
373 		return ret;
374 
375 	ret = ultrarisc_clk_register_fixed_factors(dev, clk_data, soc_data);
376 	if (ret)
377 		return ret;
378 
379 	ret = ultrarisc_clk_register_dividers(pdev, clk_data, soc_data, base, lock);
380 	if (ret)
381 		return ret;
382 
383 	ret = ultrarisc_clk_register_gates(pdev, clk_data, soc_data, base, lock);
384 	if (ret)
385 		return ret;
386 
387 	for (int i = 0; i < clk_data->num; i++) {
388 		if (!clk_data->hws[i]) {
389 			dev_err(dev, "missing clock ID %u\n", i);
390 			return -EINVAL;
391 		}
392 	}
393 
394 	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
395 }
396 EXPORT_SYMBOL_NS_GPL(ultrarisc_clk_probe, "CLK_ULTRARISC");
397 
398 MODULE_DESCRIPTION("UltraRISC clock core driver");
399 MODULE_LICENSE("GPL");
400