File Index
Files and directories
Sign in
FILE

clk-ma35d1-pll.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/nuvoton/clk-ma35d1-pll.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2023 Nuvoton Technology Corp.
  4 * Author: Chi-Fang Li <cfli0@nuvoton.com>
  5 */
  6
  7#include <linux/bitfield.h>
  8#include <linux/clk-provider.h>
  9#include <linux/container_of.h>
 10#include <linux/device.h>
 11#include <linux/io.h>
 12#include <linux/kernel.h>
 13#include <linux/math64.h>
 14#include <linux/slab.h>
 15#include <linux/units.h>
 16#include <dt-bindings/clock/nuvoton,ma35d1-clk.h>
 17
 18#include "clk-ma35d1.h"
 19
 20/* PLL frequency limits */
 21#define PLL_FREF_MAX_FREQ	(200 * HZ_PER_MHZ)
 22#define PLL_FREF_MIN_FREQ	(1 * HZ_PER_MHZ)
 23#define PLL_FREF_M_MAX_FREQ	(40 * HZ_PER_MHZ)
 24#define PLL_FREF_M_MIN_FREQ	(10 * HZ_PER_MHZ)
 25#define PLL_FCLK_MAX_FREQ	(2400 * HZ_PER_MHZ)
 26#define PLL_FCLK_MIN_FREQ	(600 * HZ_PER_MHZ)
 27#define PLL_FCLKO_MAX_FREQ	(2400 * HZ_PER_MHZ)
 28#define PLL_FCLKO_MIN_FREQ	(85700 * HZ_PER_KHZ)
 29#define PLL_SS_RATE		0x77
 30#define PLL_SLOPE		0x58CFA
 31
 32#define REG_PLL_CTL0_OFFSET	0x0
 33#define REG_PLL_CTL1_OFFSET	0x4
 34#define REG_PLL_CTL2_OFFSET	0x8
 35
 36/* bit fields for REG_CLK_PLL0CTL0, which is SMIC PLL design */
 37#define SPLL0_CTL0_FBDIV	GENMASK(7, 0)
 38#define SPLL0_CTL0_INDIV	GENMASK(11, 8)
 39#define SPLL0_CTL0_OUTDIV	GENMASK(13, 12)
 40#define SPLL0_CTL0_PD		BIT(16)
 41#define SPLL0_CTL0_BP		BIT(17)
 42
 43/* bit fields for REG_CLK_PLLxCTL0 ~ REG_CLK_PLLxCTL2, where x = 2 ~ 5 */
 44#define PLL_CTL0_FBDIV		GENMASK(10, 0)
 45#define PLL_CTL0_INDIV		GENMASK(17, 12)
 46#define PLL_CTL0_MODE		GENMASK(19, 18)
 47#define PLL_CTL0_SSRATE		GENMASK(30, 20)
 48#define PLL_CTL1_PD		BIT(0)
 49#define PLL_CTL1_BP		BIT(1)
 50#define PLL_CTL1_OUTDIV		GENMASK(6, 4)
 51#define PLL_CTL1_FRAC		GENMASK(31, 24)
 52#define PLL_CTL2_SLOPE		GENMASK(23, 0)
 53
 54#define INDIV_MIN		1
 55#define INDIV_MAX		63
 56#define FBDIV_MIN		16
 57#define FBDIV_MAX		2047
 58#define FBDIV_FRAC_MIN		1600
 59#define FBDIV_FRAC_MAX		204700
 60#define OUTDIV_MIN		1
 61#define OUTDIV_MAX		7
 62
 63#define PLL_MODE_INT            0
 64#define PLL_MODE_FRAC           1
 65#define PLL_MODE_SS             2
 66
 67struct ma35d1_clk_pll {
 68	struct clk_hw hw;
 69	u32 id;
 70	u8 mode;
 71	void __iomem *ctl0_base;
 72	void __iomem *ctl1_base;
 73	void __iomem *ctl2_base;
 74};
 75
 76static inline struct ma35d1_clk_pll *to_ma35d1_clk_pll(struct clk_hw *_hw)
 77{
 78	return container_of(_hw, struct ma35d1_clk_pll, hw);
 79}
 80
 81static unsigned long ma35d1_calc_smic_pll_freq(u32 pll0_ctl0,
 82					       unsigned long parent_rate)
 83{
 84	u32 m, n, p, outdiv;
 85	u64 pll_freq;
 86
 87	if (pll0_ctl0 & SPLL0_CTL0_BP)
 88		return parent_rate;
 89
 90	n = FIELD_GET(SPLL0_CTL0_FBDIV, pll0_ctl0);
 91	m = FIELD_GET(SPLL0_CTL0_INDIV, pll0_ctl0);
 92	p = FIELD_GET(SPLL0_CTL0_OUTDIV, pll0_ctl0);
 93	outdiv = 1 << p;
 94	pll_freq = (u64)parent_rate * n;
 95	div_u64(pll_freq, m * outdiv);
 96	return pll_freq;
 97}
 98
 99static unsigned long ma35d1_calc_pll_freq(u8 mode, u32 *reg_ctl, unsigned long parent_rate)
100{
101	unsigned long pll_freq, x;
102	u32 m, n, p;
103
104	if (reg_ctl[1] & PLL_CTL1_BP)
105		return parent_rate;
106
107	n = FIELD_GET(PLL_CTL0_FBDIV, reg_ctl[0]);
108	m = FIELD_GET(PLL_CTL0_INDIV, reg_ctl[0]);
109	p = FIELD_GET(PLL_CTL1_OUTDIV, reg_ctl[1]);
110
111	if (mode == PLL_MODE_INT) {
112		pll_freq = (u64)parent_rate * n;
113		div_u64(pll_freq, m * p);
114	} else {
115		x = FIELD_GET(PLL_CTL1_FRAC, reg_ctl[1]);
116		/* 2 decimal places floating to integer (ex. 1.23 to 123) */
117		n = n * 100 + ((x * 100) / FIELD_MAX(PLL_CTL1_FRAC));
118		pll_freq = div_u64(parent_rate * n, 100 * m * p);
119	}
120	return pll_freq;
121}
122
123static int ma35d1_pll_find_closest(struct ma35d1_clk_pll *pll, unsigned long rate,
124				   unsigned long parent_rate, u32 *reg_ctl,
125				   unsigned long *freq)
126{
127	unsigned long min_diff = ULONG_MAX;
128	int fbdiv_min, fbdiv_max;
129	int p, m, n;
130
131	*freq = 0;
132	if (rate < PLL_FCLKO_MIN_FREQ || rate > PLL_FCLKO_MAX_FREQ)
133		return -EINVAL;
134
135	if (pll->mode == PLL_MODE_INT) {
136		fbdiv_min = FBDIV_MIN;
137		fbdiv_max = FBDIV_MAX;
138	} else {
139		fbdiv_min = FBDIV_FRAC_MIN;
140		fbdiv_max = FBDIV_FRAC_MAX;
141	}
142
143	for (m = INDIV_MIN; m <= INDIV_MAX; m++) {
144		for (n = fbdiv_min; n <= fbdiv_max; n++) {
145			for (p = OUTDIV_MIN; p <= OUTDIV_MAX; p++) {
146				unsigned long tmp, fout, fclk, diff;
147
148				tmp = div_u64(parent_rate, m);
149				if (tmp < PLL_FREF_M_MIN_FREQ ||
150				    tmp > PLL_FREF_M_MAX_FREQ)
151					continue; /* constrain */
152
153				fclk = div_u64(parent_rate * n, m);
154				/* for 2 decimal places */
155				if (pll->mode != PLL_MODE_INT)
156					fclk = div_u64(fclk, 100);
157
158				if (fclk < PLL_FCLK_MIN_FREQ ||
159				    fclk > PLL_FCLK_MAX_FREQ)
160					continue; /* constrain */
161
162				fout = div_u64(fclk, p);
163				if (fout < PLL_FCLKO_MIN_FREQ ||
164				    fout > PLL_FCLKO_MAX_FREQ)
165					continue; /* constrain */
166
167				diff = abs(rate - fout);
168				if (diff < min_diff) {
169					reg_ctl[0] = FIELD_PREP(PLL_CTL0_INDIV, m) |
170						     FIELD_PREP(PLL_CTL0_FBDIV, n);
171					reg_ctl[1] = FIELD_PREP(PLL_CTL1_OUTDIV, p);
172					*freq = fout;
173					min_diff = diff;
174					if (min_diff == 0)
175						break;
176				}
177			}
178		}
179	}
180	if (*freq == 0)
181		return -EINVAL; /* cannot find even one valid setting */
182	return 0;
183}
184
185static int ma35d1_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
186				   unsigned long parent_rate)
187{
188	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
189	u32 reg_ctl[3] = { 0 };
190	unsigned long pll_freq;
191	int ret;
192
193	if (parent_rate < PLL_FREF_MIN_FREQ || parent_rate > PLL_FREF_MAX_FREQ)
194		return -EINVAL;
195
196	ret = ma35d1_pll_find_closest(pll, rate, parent_rate, reg_ctl, &pll_freq);
197	if (ret != 0)
198		return ret;
199
200	switch (pll->mode) {
201	case PLL_MODE_INT:
202		reg_ctl[0] |= FIELD_PREP(PLL_CTL0_MODE, PLL_MODE_INT);
203		break;
204	case PLL_MODE_FRAC:
205		reg_ctl[0] |= FIELD_PREP(PLL_CTL0_MODE, PLL_MODE_FRAC);
206		break;
207	case PLL_MODE_SS:
208		reg_ctl[0] |= FIELD_PREP(PLL_CTL0_MODE, PLL_MODE_SS) |
209			      FIELD_PREP(PLL_CTL0_SSRATE, PLL_SS_RATE);
210		reg_ctl[2] = FIELD_PREP(PLL_CTL2_SLOPE, PLL_SLOPE);
211		break;
212	}
213	reg_ctl[1] |= PLL_CTL1_PD;
214
215	writel_relaxed(reg_ctl[0], pll->ctl0_base);
216	writel_relaxed(reg_ctl[1], pll->ctl1_base);
217	writel_relaxed(reg_ctl[2], pll->ctl2_base);
218	return 0;
219}
220
221static unsigned long ma35d1_clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
222{
223	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
224	u32 reg_ctl[3];
225	unsigned long pll_freq;
226
227	if (parent_rate < PLL_FREF_MIN_FREQ || parent_rate > PLL_FREF_MAX_FREQ)
228		return 0;
229
230	switch (pll->id) {
231	case CAPLL:
232		reg_ctl[0] = readl_relaxed(pll->ctl0_base);
233		pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], parent_rate);
234		return pll_freq;
235	case DDRPLL:
236	case APLL:
237	case EPLL:
238	case VPLL:
239		reg_ctl[0] = readl_relaxed(pll->ctl0_base);
240		reg_ctl[1] = readl_relaxed(pll->ctl1_base);
241		pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, parent_rate);
242		return pll_freq;
243	}
244	return 0;
245}
246
247static int ma35d1_clk_pll_determine_rate(struct clk_hw *hw,
248					 struct clk_rate_request *req)
249{
250	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
251	u32 reg_ctl[3] = { 0 };
252	unsigned long pll_freq;
253	long ret;
254
255	if (req->best_parent_rate < PLL_FREF_MIN_FREQ || req->best_parent_rate > PLL_FREF_MAX_FREQ)
256		return -EINVAL;
257
258	ret = ma35d1_pll_find_closest(pll, req->rate, req->best_parent_rate,
259				      reg_ctl, &pll_freq);
260	if (ret < 0)
261		return ret;
262
263	switch (pll->id) {
264	case CAPLL:
265		reg_ctl[0] = readl_relaxed(pll->ctl0_base);
266		pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], req->best_parent_rate);
267		req->rate = pll_freq;
268
269		return 0;
270	case DDRPLL:
271	case APLL:
272	case EPLL:
273	case VPLL:
274		reg_ctl[0] = readl_relaxed(pll->ctl0_base);
275		reg_ctl[1] = readl_relaxed(pll->ctl1_base);
276		pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, req->best_parent_rate);
277		req->rate = pll_freq;
278
279		return 0;
280	}
281
282	req->rate = 0;
283
284	return 0;
285}
286
287static int ma35d1_clk_pll_is_prepared(struct clk_hw *hw)
288{
289	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
290	u32 val = readl_relaxed(pll->ctl1_base);
291
292	return !(val & PLL_CTL1_PD);
293}
294
295static int ma35d1_clk_pll_prepare(struct clk_hw *hw)
296{
297	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
298	u32 val;
299
300	val = readl_relaxed(pll->ctl1_base);
301	val &= ~PLL_CTL1_PD;
302	writel_relaxed(val, pll->ctl1_base);
303	return 0;
304}
305
306static void ma35d1_clk_pll_unprepare(struct clk_hw *hw)
307{
308	struct ma35d1_clk_pll *pll = to_ma35d1_clk_pll(hw);
309	u32 val;
310
311	val = readl_relaxed(pll->ctl1_base);
312	val |= PLL_CTL1_PD;
313	writel_relaxed(val, pll->ctl1_base);
314}
315
316static const struct clk_ops ma35d1_clk_pll_ops = {
317	.is_prepared = ma35d1_clk_pll_is_prepared,
318	.prepare = ma35d1_clk_pll_prepare,
319	.unprepare = ma35d1_clk_pll_unprepare,
320	.set_rate = ma35d1_clk_pll_set_rate,
321	.recalc_rate = ma35d1_clk_pll_recalc_rate,
322	.determine_rate = ma35d1_clk_pll_determine_rate,
323};
324
325static const struct clk_ops ma35d1_clk_fixed_pll_ops = {
326	.recalc_rate = ma35d1_clk_pll_recalc_rate,
327	.determine_rate = ma35d1_clk_pll_determine_rate,
328};
329
330struct clk_hw *ma35d1_reg_clk_pll(struct device *dev, u32 id, u8 u8mode, const char *name,
331				  struct clk_hw *parent_hw, void __iomem *base)
332{
333	struct clk_parent_data pdata = { .index = 0 };
334	struct clk_init_data init = {};
335	struct ma35d1_clk_pll *pll;
336	struct clk_hw *hw;
337	int ret;
338
339	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
340	if (!pll)
341		return ERR_PTR(-ENOMEM);
342
343	pll->id = id;
344	pll->mode = u8mode;
345	pll->ctl0_base = base + REG_PLL_CTL0_OFFSET;
346	pll->ctl1_base = base + REG_PLL_CTL1_OFFSET;
347	pll->ctl2_base = base + REG_PLL_CTL2_OFFSET;
348
349	init.name = name;
350	init.flags = 0;
351	pdata.hw = parent_hw;
352	init.parent_data = &pdata;
353	init.num_parents = 1;
354
355	if (id == CAPLL || id == DDRPLL)
356		init.ops = &ma35d1_clk_fixed_pll_ops;
357	else
358		init.ops = &ma35d1_clk_pll_ops;
359
360	pll->hw.init = &init;
361	hw = &pll->hw;
362
363	ret = devm_clk_hw_register(dev, hw);
364	if (ret)
365		return ERR_PTR(ret);
366	return hw;
367}
368EXPORT_SYMBOL_GPL(ma35d1_reg_clk_pll);
~/ Read-only file preview.