File Index
Files and directories
Sign in
FILE

pll.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/visconti/pll.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Toshiba Visconti PLL driver
  4 *
  5 * Copyright (c) 2021 TOSHIBA CORPORATION
  6 * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
  7 *
  8 * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
  9 */
 10
 11#include <linux/bitfield.h>
 12#include <linux/clk-provider.h>
 13#include <linux/delay.h>
 14#include <linux/slab.h>
 15#include <linux/io.h>
 16
 17#include "pll.h"
 18
 19struct visconti_pll {
 20	struct clk_hw	hw;
 21	void __iomem	*pll_base;
 22	spinlock_t	*lock;
 23	unsigned long flags;
 24	const struct visconti_pll_rate_table *rate_table;
 25	size_t rate_count;
 26	struct visconti_pll_provider *ctx;
 27};
 28
 29#define PLL_CONF_REG		0x0000
 30#define PLL_CTRL_REG		0x0004
 31#define PLL_FRACMODE_REG	0x0010
 32#define PLL_INTIN_REG		0x0014
 33#define PLL_FRACIN_REG		0x0018
 34#define PLL_REFDIV_REG		0x001c
 35#define PLL_POSTDIV_REG		0x0020
 36
 37#define PLL_CONFIG_SEL		BIT(0)
 38#define PLL_PLLEN		BIT(4)
 39#define PLL_BYPASS		BIT(16)
 40#define PLL_INTIN_MASK		GENMASK(11, 0)
 41#define PLL_FRACIN_MASK		GENMASK(23, 0)
 42#define PLL_REFDIV_MASK		GENMASK(5, 0)
 43#define PLL_POSTDIV_MASK	GENMASK(2, 0)
 44
 45#define PLL0_FRACMODE_DACEN	BIT(4)
 46#define PLL0_FRACMODE_DSMEN	BIT(0)
 47
 48#define PLL_CREATE_FRACMODE(table) (table->dacen << 4 | table->dsmen)
 49#define PLL_CREATE_OSTDIV(table) (table->postdiv2 << 4 | table->postdiv1)
 50
 51static inline struct visconti_pll *to_visconti_pll(struct clk_hw *hw)
 52{
 53	return container_of(hw, struct visconti_pll, hw);
 54}
 55
 56static void visconti_pll_get_params(struct visconti_pll *pll,
 57				    struct visconti_pll_rate_table *rate_table)
 58{
 59	u32 postdiv, val;
 60
 61	val = readl(pll->pll_base + PLL_FRACMODE_REG);
 62
 63	rate_table->dacen = FIELD_GET(PLL0_FRACMODE_DACEN, val);
 64	rate_table->dsmen = FIELD_GET(PLL0_FRACMODE_DSMEN, val);
 65
 66	rate_table->fracin = readl(pll->pll_base + PLL_FRACIN_REG) & PLL_FRACIN_MASK;
 67	rate_table->intin = readl(pll->pll_base + PLL_INTIN_REG) & PLL_INTIN_MASK;
 68	rate_table->refdiv = readl(pll->pll_base + PLL_REFDIV_REG) & PLL_REFDIV_MASK;
 69
 70	postdiv = readl(pll->pll_base + PLL_POSTDIV_REG);
 71	rate_table->postdiv1 = postdiv & PLL_POSTDIV_MASK;
 72	rate_table->postdiv2 = (postdiv >> 4) & PLL_POSTDIV_MASK;
 73}
 74
 75static const struct visconti_pll_rate_table *visconti_get_pll_settings(struct visconti_pll *pll,
 76								       unsigned long rate)
 77{
 78	const struct visconti_pll_rate_table *rate_table = pll->rate_table;
 79	int i;
 80
 81	for (i = 0; i < pll->rate_count; i++)
 82		if (rate == rate_table[i].rate)
 83			return &rate_table[i];
 84
 85	return NULL;
 86}
 87
 88static unsigned long visconti_get_pll_rate_from_data(struct visconti_pll *pll,
 89						     const struct visconti_pll_rate_table *rate)
 90{
 91	const struct visconti_pll_rate_table *rate_table = pll->rate_table;
 92	int i;
 93
 94	for (i = 0; i < pll->rate_count; i++)
 95		if (memcmp(&rate_table[i].dacen, &rate->dacen,
 96			sizeof(*rate) - sizeof(unsigned long)) == 0)
 97			return rate_table[i].rate;
 98
 99	/* set default */
100	return rate_table[0].rate;
101}
102
103static int visconti_pll_determine_rate(struct clk_hw *hw,
104				       struct clk_rate_request *req)
105{
106	struct visconti_pll *pll = to_visconti_pll(hw);
107	const struct visconti_pll_rate_table *rate_table = pll->rate_table;
108	int i;
109
110	/* Assuming rate_table is in descending order */
111	for (i = 0; i < pll->rate_count; i++)
112		if (req->rate >= rate_table[i].rate) {
113			req->rate = rate_table[i].rate;
114
115			return 0;
116		}
117
118	/* return minimum supported value */
119	req->rate = rate_table[i - 1].rate;
120
121	return 0;
122}
123
124static unsigned long visconti_pll_recalc_rate(struct clk_hw *hw,
125					      unsigned long parent_rate)
126{
127	struct visconti_pll *pll = to_visconti_pll(hw);
128	struct visconti_pll_rate_table rate_table;
129
130	memset(&rate_table, 0, sizeof(rate_table));
131	visconti_pll_get_params(pll, &rate_table);
132
133	return visconti_get_pll_rate_from_data(pll, &rate_table);
134}
135
136static int visconti_pll_set_params(struct visconti_pll *pll,
137				   const struct visconti_pll_rate_table *rate_table)
138{
139	writel(PLL_CREATE_FRACMODE(rate_table), pll->pll_base + PLL_FRACMODE_REG);
140	writel(PLL_CREATE_OSTDIV(rate_table), pll->pll_base + PLL_POSTDIV_REG);
141	writel(rate_table->intin, pll->pll_base + PLL_INTIN_REG);
142	writel(rate_table->fracin, pll->pll_base + PLL_FRACIN_REG);
143	writel(rate_table->refdiv, pll->pll_base + PLL_REFDIV_REG);
144
145	return 0;
146}
147
148static int visconti_pll_set_rate(struct clk_hw *hw, unsigned long rate,
149			    unsigned long parent_rate)
150{
151	struct visconti_pll *pll = to_visconti_pll(hw);
152	const struct visconti_pll_rate_table *rate_table;
153
154	rate_table = visconti_get_pll_settings(pll, rate);
155	if (!rate_table)
156		return -EINVAL;
157
158	return visconti_pll_set_params(pll, rate_table);
159}
160
161static int visconti_pll_is_enabled(struct clk_hw *hw)
162{
163	struct visconti_pll *pll = to_visconti_pll(hw);
164	u32 reg;
165
166	reg = readl(pll->pll_base + PLL_CTRL_REG);
167
168	return (reg & PLL_PLLEN);
169}
170
171static int visconti_pll_enable(struct clk_hw *hw)
172{
173	struct visconti_pll *pll = to_visconti_pll(hw);
174	const struct visconti_pll_rate_table *rate_table = pll->rate_table;
175	unsigned long flags;
176	u32 reg;
177
178	if (visconti_pll_is_enabled(hw))
179		return 0;
180
181	spin_lock_irqsave(pll->lock, flags);
182
183	writel(PLL_CONFIG_SEL, pll->pll_base + PLL_CONF_REG);
184
185	reg = readl(pll->pll_base + PLL_CTRL_REG);
186	reg |= PLL_BYPASS;
187	writel(reg, pll->pll_base + PLL_CTRL_REG);
188
189	visconti_pll_set_params(pll, &rate_table[0]);
190
191	reg = readl(pll->pll_base + PLL_CTRL_REG);
192	reg &= ~PLL_PLLEN;
193	writel(reg, pll->pll_base + PLL_CTRL_REG);
194
195	udelay(1);
196
197	reg = readl(pll->pll_base + PLL_CTRL_REG);
198	reg |= PLL_PLLEN;
199	writel(reg, pll->pll_base + PLL_CTRL_REG);
200
201	udelay(40);
202
203	reg = readl(pll->pll_base + PLL_CTRL_REG);
204	reg &= ~PLL_BYPASS;
205	writel(reg, pll->pll_base + PLL_CTRL_REG);
206
207	spin_unlock_irqrestore(pll->lock, flags);
208
209	return 0;
210}
211
212static void visconti_pll_disable(struct clk_hw *hw)
213{
214	struct visconti_pll *pll = to_visconti_pll(hw);
215	unsigned long flags;
216	u32 reg;
217
218	if (!visconti_pll_is_enabled(hw))
219		return;
220
221	spin_lock_irqsave(pll->lock, flags);
222
223	writel(PLL_CONFIG_SEL, pll->pll_base + PLL_CONF_REG);
224
225	reg = readl(pll->pll_base + PLL_CTRL_REG);
226	reg |= PLL_BYPASS;
227	writel(reg, pll->pll_base + PLL_CTRL_REG);
228
229	reg = readl(pll->pll_base + PLL_CTRL_REG);
230	reg &= ~PLL_PLLEN;
231	writel(reg, pll->pll_base + PLL_CTRL_REG);
232
233	spin_unlock_irqrestore(pll->lock, flags);
234}
235
236static const struct clk_ops visconti_pll_ops = {
237	.enable = visconti_pll_enable,
238	.disable = visconti_pll_disable,
239	.is_enabled = visconti_pll_is_enabled,
240	.determine_rate = visconti_pll_determine_rate,
241	.recalc_rate = visconti_pll_recalc_rate,
242	.set_rate = visconti_pll_set_rate,
243};
244
245static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx,
246					    const char *name,
247					    const char *parent_name,
248					    int offset,
249					    const struct visconti_pll_rate_table *rate_table,
250					    spinlock_t *lock)
251{
252	struct clk_init_data init;
253	struct visconti_pll *pll;
254	struct clk_hw *pll_hw_clk;
255	size_t len;
256	int ret;
257
258	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
259	if (!pll)
260		return ERR_PTR(-ENOMEM);
261
262	init.name = name;
263	init.flags = CLK_IGNORE_UNUSED;
264	init.parent_names = &parent_name;
265	init.num_parents = 1;
266
267	for (len = 0; rate_table[len].rate != 0; )
268		len++;
269	pll->rate_count = len;
270	pll->rate_table = kmemdup_array(rate_table,
271					pll->rate_count, sizeof(*pll->rate_table),
272					GFP_KERNEL);
273	WARN(!pll->rate_table, "%s: could not allocate rate table for %s\n", __func__, name);
274
275	init.ops = &visconti_pll_ops;
276	pll->hw.init = &init;
277	pll->pll_base = ctx->reg_base + offset;
278	pll->lock = lock;
279	pll->ctx = ctx;
280
281	pll_hw_clk = &pll->hw;
282	ret = clk_hw_register(NULL, &pll->hw);
283	if (ret) {
284		pr_err("failed to register pll clock %s : %d\n", name, ret);
285		kfree(pll->rate_table);
286		kfree(pll);
287		pll_hw_clk = ERR_PTR(ret);
288	}
289
290	return pll_hw_clk;
291}
292
293static void visconti_pll_add_lookup(struct visconti_pll_provider *ctx,
294				    struct clk_hw *hw_clk,
295				    unsigned int id)
296{
297	if (id)
298		ctx->clk_data.hws[id] = hw_clk;
299}
300
301void __init visconti_register_plls(struct visconti_pll_provider *ctx,
302				   const struct visconti_pll_info *list,
303				   unsigned int nr_plls,
304				   spinlock_t *lock)
305{
306	int idx;
307
308	for (idx = 0; idx < nr_plls; idx++, list++) {
309		struct clk_hw *clk;
310
311		clk = visconti_register_pll(ctx,
312					    list->name,
313					    list->parent,
314					    list->base_reg,
315					    list->rate_table,
316					    lock);
317		if (IS_ERR(clk)) {
318			pr_err("failed to register clock %s\n", list->name);
319			continue;
320		}
321
322		visconti_pll_add_lookup(ctx, clk, list->id);
323	}
324}
325
326struct visconti_pll_provider * __init visconti_init_pll(struct device_node *np,
327							void __iomem *base,
328							unsigned long nr_plls)
329{
330	struct visconti_pll_provider *ctx;
331	int i;
332
333	ctx = kzalloc(struct_size(ctx, clk_data.hws, nr_plls), GFP_KERNEL);
334	if (!ctx)
335		return ERR_PTR(-ENOMEM);
336
337	ctx->node = np;
338	ctx->reg_base = base;
339	ctx->clk_data.num = nr_plls;
340
341	for (i = 0; i < nr_plls; ++i)
342		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
343
344	return ctx;
345}
~/ Read-only file preview.