xref: /linux/drivers/clk/qcom/common.c (revision 22c55fb9eb92395d999b8404d73e58540d11bdd8)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
4  */
5 
6 #include <linux/export.h>
7 #include <linux/module.h>
8 #include <linux/regmap.h>
9 #include <linux/platform_device.h>
10 #include <linux/clk-provider.h>
11 #include <linux/interconnect-clk.h>
12 #include <linux/pm_runtime.h>
13 #include <linux/reset-controller.h>
14 #include <linux/of.h>
15 
16 #include "common.h"
17 #include "clk-alpha-pll.h"
18 #include "clk-branch.h"
19 #include "clk-rcg.h"
20 #include "clk-regmap.h"
21 #include "reset.h"
22 #include "gdsc.h"
23 
24 struct qcom_cc {
25 	struct qcom_reset_controller reset;
26 	struct clk_regmap **rclks;
27 	size_t num_rclks;
28 	struct dev_pm_domain_list *pd_list;
29 };
30 
31 const
32 struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate)
33 {
34 	if (!f)
35 		return NULL;
36 
37 	if (!f->freq)
38 		return f;
39 
40 	for (; f->freq; f++)
41 		if (rate <= f->freq)
42 			return f;
43 
44 	/* Default to our fastest rate */
45 	return f - 1;
46 }
47 EXPORT_SYMBOL_GPL(qcom_find_freq);
48 
49 const struct freq_multi_tbl *qcom_find_freq_multi(const struct freq_multi_tbl *f,
50 						  unsigned long rate)
51 {
52 	if (!f)
53 		return NULL;
54 
55 	if (!f->freq)
56 		return f;
57 
58 	for (; f->freq; f++)
59 		if (rate <= f->freq)
60 			return f;
61 
62 	/* Default to our fastest rate */
63 	return f - 1;
64 }
65 EXPORT_SYMBOL_GPL(qcom_find_freq_multi);
66 
67 const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,
68 					    unsigned long rate)
69 {
70 	const struct freq_tbl *best = NULL;
71 
72 	for ( ; f->freq; f++) {
73 		if (rate >= f->freq)
74 			best = f;
75 		else
76 			break;
77 	}
78 
79 	return best;
80 }
81 EXPORT_SYMBOL_GPL(qcom_find_freq_floor);
82 
83 int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map, u8 src)
84 {
85 	int i, num_parents = clk_hw_get_num_parents(hw);
86 
87 	for (i = 0; i < num_parents; i++)
88 		if (src == map[i].src)
89 			return i;
90 
91 	return -ENOENT;
92 }
93 EXPORT_SYMBOL_GPL(qcom_find_src_index);
94 
95 int qcom_find_cfg_index(struct clk_hw *hw, const struct parent_map *map, u8 cfg)
96 {
97 	int i, num_parents = clk_hw_get_num_parents(hw);
98 
99 	for (i = 0; i < num_parents; i++)
100 		if (cfg == map[i].cfg)
101 			return i;
102 
103 	return -ENOENT;
104 }
105 EXPORT_SYMBOL_GPL(qcom_find_cfg_index);
106 
107 struct regmap *
108 qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc)
109 {
110 	void __iomem *base;
111 	struct device *dev = &pdev->dev;
112 
113 	base = devm_platform_ioremap_resource(pdev, 0);
114 	if (IS_ERR(base))
115 		return ERR_CAST(base);
116 
117 	return devm_regmap_init_mmio(dev, base, desc->config);
118 }
119 EXPORT_SYMBOL_GPL(qcom_cc_map);
120 
121 void
122 qcom_pll_set_fsm_mode(struct regmap *map, u32 reg, u8 bias_count, u8 lock_count)
123 {
124 	u32 val;
125 	u32 mask;
126 
127 	/* De-assert reset to FSM */
128 	regmap_update_bits(map, reg, PLL_VOTE_FSM_RESET, 0);
129 
130 	/* Program bias count and lock count */
131 	val = bias_count << PLL_BIAS_COUNT_SHIFT |
132 		lock_count << PLL_LOCK_COUNT_SHIFT;
133 	mask = PLL_BIAS_COUNT_MASK << PLL_BIAS_COUNT_SHIFT;
134 	mask |= PLL_LOCK_COUNT_MASK << PLL_LOCK_COUNT_SHIFT;
135 	regmap_update_bits(map, reg, mask, val);
136 
137 	/* Enable PLL FSM voting */
138 	regmap_update_bits(map, reg, PLL_VOTE_FSM_ENA, PLL_VOTE_FSM_ENA);
139 }
140 EXPORT_SYMBOL_GPL(qcom_pll_set_fsm_mode);
141 
142 static void qcom_cc_gdsc_unregister(void *data)
143 {
144 	gdsc_unregister(data);
145 }
146 
147 /*
148  * Backwards compatibility with old DTs. Register a pass-through factor 1/1
149  * clock to translate 'path' clk into 'name' clk and register the 'path'
150  * clk as a fixed rate clock if it isn't present.
151  */
152 static int _qcom_cc_register_board_clk(struct device *dev, const char *path,
153 				       const char *name, unsigned long rate,
154 				       bool add_factor)
155 {
156 	struct device_node *node = NULL;
157 	struct device_node *clocks_node;
158 	struct clk_fixed_factor *factor;
159 	struct clk_fixed_rate *fixed;
160 	struct clk_init_data init_data = { };
161 	int ret;
162 
163 	clocks_node = of_find_node_by_path("/clocks");
164 	if (clocks_node) {
165 		node = of_get_child_by_name(clocks_node, path);
166 		of_node_put(clocks_node);
167 	}
168 
169 	if (!node) {
170 		fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL);
171 		if (!fixed)
172 			return -EINVAL;
173 
174 		fixed->fixed_rate = rate;
175 		fixed->hw.init = &init_data;
176 
177 		init_data.name = path;
178 		init_data.ops = &clk_fixed_rate_ops;
179 
180 		ret = devm_clk_hw_register(dev, &fixed->hw);
181 		if (ret)
182 			return ret;
183 	}
184 	of_node_put(node);
185 
186 	if (add_factor) {
187 		factor = devm_kzalloc(dev, sizeof(*factor), GFP_KERNEL);
188 		if (!factor)
189 			return -EINVAL;
190 
191 		factor->mult = factor->div = 1;
192 		factor->hw.init = &init_data;
193 
194 		init_data.name = name;
195 		init_data.parent_names = &path;
196 		init_data.num_parents = 1;
197 		init_data.flags = 0;
198 		init_data.ops = &clk_fixed_factor_ops;
199 
200 		ret = devm_clk_hw_register(dev, &factor->hw);
201 		if (ret)
202 			return ret;
203 	}
204 
205 	return 0;
206 }
207 
208 int qcom_cc_register_board_clk(struct device *dev, const char *path,
209 			       const char *name, unsigned long rate)
210 {
211 	bool add_factor = true;
212 
213 	/*
214 	 * TODO: The RPM clock driver currently does not support the xo clock.
215 	 * When xo is added to the RPM clock driver, we should change this
216 	 * function to skip registration of xo factor clocks.
217 	 */
218 
219 	return _qcom_cc_register_board_clk(dev, path, name, rate, add_factor);
220 }
221 EXPORT_SYMBOL_GPL(qcom_cc_register_board_clk);
222 
223 int qcom_cc_register_sleep_clk(struct device *dev)
224 {
225 	return _qcom_cc_register_board_clk(dev, "sleep_clk", "sleep_clk_src",
226 					   32768, true);
227 }
228 EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk);
229 
230 /* Drop 'protected-clocks' from the list of clocks to register */
231 static void qcom_cc_drop_protected(struct device *dev, struct qcom_cc *cc)
232 {
233 	struct device_node *np = dev->of_node;
234 	u32 i;
235 
236 	of_property_for_each_u32(np, "protected-clocks", i) {
237 		if (i >= cc->num_rclks)
238 			continue;
239 
240 		cc->rclks[i] = NULL;
241 	}
242 }
243 
244 static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec,
245 					 void *data)
246 {
247 	struct qcom_cc *cc = data;
248 	unsigned int idx = clkspec->args[0];
249 
250 	if (idx >= cc->num_rclks) {
251 		pr_err("%s: invalid index %u\n", __func__, idx);
252 		return ERR_PTR(-EINVAL);
253 	}
254 
255 	return cc->rclks[idx] ? &cc->rclks[idx]->hw : NULL;
256 }
257 
258 static int qcom_cc_icc_register(struct device *dev,
259 				const struct qcom_cc_desc *desc)
260 {
261 	struct icc_clk_data *icd;
262 	struct clk_hw *hws;
263 	int i;
264 
265 	if (!IS_ENABLED(CONFIG_INTERCONNECT_CLK))
266 		return 0;
267 
268 	if (!desc->icc_hws)
269 		return 0;
270 
271 	icd = devm_kcalloc(dev, desc->num_icc_hws, sizeof(*icd), GFP_KERNEL);
272 	if (!icd)
273 		return -ENOMEM;
274 
275 	for (i = 0; i < desc->num_icc_hws; i++) {
276 		icd[i].master_id = desc->icc_hws[i].master_id;
277 		icd[i].slave_id = desc->icc_hws[i].slave_id;
278 		hws = &desc->clks[desc->icc_hws[i].clk_id]->hw;
279 		icd[i].clk = devm_clk_hw_get_clk(dev, hws, "icc");
280 		if (!icd[i].clk)
281 			return dev_err_probe(dev, -ENOENT,
282 					     "(%d) clock entry is null\n", i);
283 		icd[i].name = clk_hw_get_name(hws);
284 	}
285 
286 	return devm_icc_clk_register(dev, desc->icc_first_node_id,
287 						     desc->num_icc_hws, icd);
288 }
289 
290 static int qcom_cc_clk_pll_configure(const struct qcom_cc_driver_data *data,
291 				     struct regmap *regmap)
292 {
293 	const struct clk_init_data *init;
294 	struct clk_alpha_pll *pll;
295 	int i;
296 
297 	for (i = 0; i < data->num_alpha_plls; i++) {
298 		pll = data->alpha_plls[i];
299 		init = pll->clkr.hw.init;
300 
301 		if (!pll->config || !pll->regs) {
302 			pr_err("%s: missing pll config or regs\n", init->name);
303 			return -EINVAL;
304 		}
305 
306 		qcom_clk_alpha_pll_configure(pll, regmap);
307 	}
308 
309 	return 0;
310 }
311 
312 static void qcom_cc_clk_regs_configure(struct device *dev, const struct qcom_cc_driver_data *data,
313 				       struct regmap *regmap)
314 {
315 	int i;
316 
317 	for (i = 0; i < data->num_clk_cbcrs; i++)
318 		qcom_branch_set_clk_en(regmap, data->clk_cbcrs[i]);
319 
320 	if (data->clk_regs_configure)
321 		data->clk_regs_configure(dev, regmap);
322 }
323 
324 int qcom_cc_really_probe(struct device *dev,
325 			 const struct qcom_cc_desc *desc, struct regmap *regmap)
326 {
327 	int i, ret;
328 	struct qcom_reset_controller *reset;
329 	struct qcom_cc *cc;
330 	struct gdsc_desc *scd;
331 	size_t num_clks = desc->num_clks;
332 	struct clk_regmap **rclks = desc->clks;
333 	size_t num_clk_hws = desc->num_clk_hws;
334 	struct clk_hw **clk_hws = desc->clk_hws;
335 
336 	cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL);
337 	if (!cc)
338 		return -ENOMEM;
339 
340 	ret = devm_pm_domain_attach_list(dev, NULL, &cc->pd_list);
341 	if (ret < 0 && ret != -EEXIST)
342 		return ret;
343 
344 	if (desc->use_rpm) {
345 		ret = devm_pm_runtime_enable(dev);
346 		if (ret)
347 			return ret;
348 
349 		ret = pm_runtime_resume_and_get(dev);
350 		if (ret)
351 			return ret;
352 	}
353 
354 	if (desc->driver_data) {
355 		ret = qcom_cc_clk_pll_configure(desc->driver_data, regmap);
356 		if (ret)
357 			goto put_rpm;
358 
359 		qcom_cc_clk_regs_configure(dev, desc->driver_data, regmap);
360 	}
361 
362 	reset = &cc->reset;
363 	reset->rcdev.of_node = dev->of_node;
364 	reset->rcdev.ops = &qcom_reset_ops;
365 	reset->rcdev.owner = dev->driver->owner;
366 	reset->rcdev.nr_resets = desc->num_resets;
367 	reset->regmap = regmap;
368 	reset->reset_map = desc->resets;
369 
370 	ret = devm_reset_controller_register(dev, &reset->rcdev);
371 	if (ret)
372 		goto put_rpm;
373 
374 	if (desc->gdscs && desc->num_gdscs) {
375 		scd = devm_kzalloc(dev, sizeof(*scd), GFP_KERNEL);
376 		if (!scd) {
377 			ret = -ENOMEM;
378 			goto put_rpm;
379 		}
380 		scd->dev = dev;
381 		scd->scs = desc->gdscs;
382 		scd->num = desc->num_gdscs;
383 		scd->pd_list = cc->pd_list;
384 		ret = gdsc_register(scd, &reset->rcdev, regmap);
385 		if (ret)
386 			goto put_rpm;
387 		ret = devm_add_action_or_reset(dev, qcom_cc_gdsc_unregister,
388 					       scd);
389 		if (ret)
390 			goto put_rpm;
391 	}
392 
393 	if (desc->driver_data &&
394 	    desc->driver_data->dfs_rcgs &&
395 	    desc->driver_data->num_dfs_rcgs) {
396 		ret = qcom_cc_register_rcg_dfs(regmap,
397 					       desc->driver_data->dfs_rcgs,
398 					       desc->driver_data->num_dfs_rcgs);
399 		if (ret)
400 			goto put_rpm;
401 	}
402 
403 	cc->rclks = rclks;
404 	cc->num_rclks = num_clks;
405 
406 	qcom_cc_drop_protected(dev, cc);
407 
408 	for (i = 0; i < num_clk_hws; i++) {
409 		ret = devm_clk_hw_register(dev, clk_hws[i]);
410 		if (ret)
411 			goto put_rpm;
412 	}
413 
414 	for (i = 0; i < num_clks; i++) {
415 		if (!rclks[i])
416 			continue;
417 
418 		ret = devm_clk_register_regmap(dev, rclks[i]);
419 		if (ret)
420 			goto put_rpm;
421 	}
422 
423 	ret = devm_of_clk_add_hw_provider(dev, qcom_cc_clk_hw_get, cc);
424 	if (ret)
425 		goto put_rpm;
426 
427 	ret = qcom_cc_icc_register(dev, desc);
428 
429 put_rpm:
430 	if (desc->use_rpm)
431 		pm_runtime_put(dev);
432 
433 	return ret;
434 }
435 EXPORT_SYMBOL_GPL(qcom_cc_really_probe);
436 
437 int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc)
438 {
439 	struct regmap *regmap;
440 
441 	regmap = qcom_cc_map(pdev, desc);
442 	if (IS_ERR(regmap))
443 		return PTR_ERR(regmap);
444 
445 	return qcom_cc_really_probe(&pdev->dev, desc, regmap);
446 }
447 EXPORT_SYMBOL_GPL(qcom_cc_probe);
448 
449 int qcom_cc_probe_by_index(struct platform_device *pdev, int index,
450 			   const struct qcom_cc_desc *desc)
451 {
452 	struct regmap *regmap;
453 	void __iomem *base;
454 
455 	base = devm_platform_ioremap_resource(pdev, index);
456 	if (IS_ERR(base))
457 		return -ENOMEM;
458 
459 	regmap = devm_regmap_init_mmio(&pdev->dev, base, desc->config);
460 	if (IS_ERR(regmap))
461 		return PTR_ERR(regmap);
462 
463 	return qcom_cc_really_probe(&pdev->dev, desc, regmap);
464 }
465 EXPORT_SYMBOL_GPL(qcom_cc_probe_by_index);
466 
467 MODULE_LICENSE("GPL v2");
468 MODULE_DESCRIPTION("QTI Common Clock module");
469