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 long visconti_pll_round_rate(struct clk_hw *hw,
104				    unsigned long rate, unsigned long *prate)
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	/* Assumming rate_table is in descending order */
111	for (i = 0; i < pll->rate_count; i++)
112		if (rate >= rate_table[i].rate)
113			return rate_table[i].rate;
114
115	/* return minimum supported value */
116	return rate_table[i - 1].rate;
117}
118
119static unsigned long visconti_pll_recalc_rate(struct clk_hw *hw,
120					      unsigned long parent_rate)
121{
122	struct visconti_pll *pll = to_visconti_pll(hw);
123	struct visconti_pll_rate_table rate_table;
124
125	memset(&rate_table, 0, sizeof(rate_table));
126	visconti_pll_get_params(pll, &rate_table);
127
128	return visconti_get_pll_rate_from_data(pll, &rate_table);
129}
130
131static int visconti_pll_set_params(struct visconti_pll *pll,
132				   const struct visconti_pll_rate_table *rate_table)
133{
134	writel(PLL_CREATE_FRACMODE(rate_table), pll->pll_base + PLL_FRACMODE_REG);
135	writel(PLL_CREATE_OSTDIV(rate_table), pll->pll_base + PLL_POSTDIV_REG);
136	writel(rate_table->intin, pll->pll_base + PLL_INTIN_REG);
137	writel(rate_table->fracin, pll->pll_base + PLL_FRACIN_REG);
138	writel(rate_table->refdiv, pll->pll_base + PLL_REFDIV_REG);
139
140	return 0;
141}
142
143static int visconti_pll_set_rate(struct clk_hw *hw, unsigned long rate,
144			    unsigned long parent_rate)
145{
146	struct visconti_pll *pll = to_visconti_pll(hw);
147	const struct visconti_pll_rate_table *rate_table;
148
149	rate_table = visconti_get_pll_settings(pll, rate);
150	if (!rate_table)
151		return -EINVAL;
152
153	return visconti_pll_set_params(pll, rate_table);
154}
155
156static int visconti_pll_is_enabled(struct clk_hw *hw)
157{
158	struct visconti_pll *pll = to_visconti_pll(hw);
159	u32 reg;
160
161	reg = readl(pll->pll_base + PLL_CTRL_REG);
162
163	return (reg & PLL_PLLEN);
164}
165
166static int visconti_pll_enable(struct clk_hw *hw)
167{
168	struct visconti_pll *pll = to_visconti_pll(hw);
169	const struct visconti_pll_rate_table *rate_table = pll->rate_table;
170	unsigned long flags;
171	u32 reg;
172
173	if (visconti_pll_is_enabled(hw))
174		return 0;
175
176	spin_lock_irqsave(pll->lock, flags);
177
178	writel(PLL_CONFIG_SEL, pll->pll_base + PLL_CONF_REG);
179
180	reg = readl(pll->pll_base + PLL_CTRL_REG);
181	reg |= PLL_BYPASS;
182	writel(reg, pll->pll_base + PLL_CTRL_REG);
183
184	visconti_pll_set_params(pll, &rate_table[0]);
185
186	reg = readl(pll->pll_base + PLL_CTRL_REG);
187	reg &= ~PLL_PLLEN;
188	writel(reg, pll->pll_base + PLL_CTRL_REG);
189
190	udelay(1);
191
192	reg = readl(pll->pll_base + PLL_CTRL_REG);
193	reg |= PLL_PLLEN;
194	writel(reg, pll->pll_base + PLL_CTRL_REG);
195
196	udelay(40);
197
198	reg = readl(pll->pll_base + PLL_CTRL_REG);
199	reg &= ~PLL_BYPASS;
200	writel(reg, pll->pll_base + PLL_CTRL_REG);
201
202	spin_unlock_irqrestore(pll->lock, flags);
203
204	return 0;
205}
206
207static void visconti_pll_disable(struct clk_hw *hw)
208{
209	struct visconti_pll *pll = to_visconti_pll(hw);
210	unsigned long flags;
211	u32 reg;
212
213	if (!visconti_pll_is_enabled(hw))
214		return;
215
216	spin_lock_irqsave(pll->lock, flags);
217
218	writel(PLL_CONFIG_SEL, pll->pll_base + PLL_CONF_REG);
219
220	reg = readl(pll->pll_base + PLL_CTRL_REG);
221	reg |= PLL_BYPASS;
222	writel(reg, pll->pll_base + PLL_CTRL_REG);
223
224	reg = readl(pll->pll_base + PLL_CTRL_REG);
225	reg &= ~PLL_PLLEN;
226	writel(reg, pll->pll_base + PLL_CTRL_REG);
227
228	spin_unlock_irqrestore(pll->lock, flags);
229}
230
231static const struct clk_ops visconti_pll_ops = {
232	.enable = visconti_pll_enable,
233	.disable = visconti_pll_disable,
234	.is_enabled = visconti_pll_is_enabled,
235	.round_rate = visconti_pll_round_rate,
236	.recalc_rate = visconti_pll_recalc_rate,
237	.set_rate = visconti_pll_set_rate,
238};
239
240static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx,
241					    const char *name,
242					    const char *parent_name,
243					    int offset,
244					    const struct visconti_pll_rate_table *rate_table,
245					    spinlock_t *lock)
246{
247	struct clk_init_data init;
248	struct visconti_pll *pll;
249	struct clk_hw *pll_hw_clk;
250	size_t len;
251	int ret;
252
253	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
254	if (!pll)
255		return ERR_PTR(-ENOMEM);
256
257	init.name = name;
258	init.flags = CLK_IGNORE_UNUSED;
259	init.parent_names = &parent_name;
260	init.num_parents = 1;
261
262	for (len = 0; rate_table[len].rate != 0; )
263		len++;
264	pll->rate_count = len;
265	pll->rate_table = kmemdup(rate_table,
266				  pll->rate_count * sizeof(struct visconti_pll_rate_table),
267				  GFP_KERNEL);
268	WARN(!pll->rate_table, "%s: could not allocate rate table for %s\n", __func__, name);
269
270	init.ops = &visconti_pll_ops;
271	pll->hw.init = &init;
272	pll->pll_base = ctx->reg_base + offset;
273	pll->lock = lock;
274	pll->ctx = ctx;
275
276	pll_hw_clk = &pll->hw;
277	ret = clk_hw_register(NULL, &pll->hw);
278	if (ret) {
279		pr_err("failed to register pll clock %s : %d\n", name, ret);
280		kfree(pll->rate_table);
281		kfree(pll);
282		pll_hw_clk = ERR_PTR(ret);
283	}
284
285	return pll_hw_clk;
286}
287
288static void visconti_pll_add_lookup(struct visconti_pll_provider *ctx,
289				    struct clk_hw *hw_clk,
290				    unsigned int id)
291{
292	if (id)
293		ctx->clk_data.hws[id] = hw_clk;
294}
295
296void __init visconti_register_plls(struct visconti_pll_provider *ctx,
297				   const struct visconti_pll_info *list,
298				   unsigned int nr_plls,
299				   spinlock_t *lock)
300{
301	int idx;
302
303	for (idx = 0; idx < nr_plls; idx++, list++) {
304		struct clk_hw *clk;
305
306		clk = visconti_register_pll(ctx,
307					    list->name,
308					    list->parent,
309					    list->base_reg,
310					    list->rate_table,
311					    lock);
312		if (IS_ERR(clk)) {
313			pr_err("failed to register clock %s\n", list->name);
314			continue;
315		}
316
317		visconti_pll_add_lookup(ctx, clk, list->id);
318	}
319}
320
321struct visconti_pll_provider * __init visconti_init_pll(struct device_node *np,
322							void __iomem *base,
323							unsigned long nr_plls)
324{
325	struct visconti_pll_provider *ctx;
326	int i;
327
328	ctx = kzalloc(struct_size(ctx, clk_data.hws, nr_plls), GFP_KERNEL);
329	if (!ctx)
330		return ERR_PTR(-ENOMEM);
331
332	ctx->node = np;
333	ctx->reg_base = base;
334	ctx->clk_data.num = nr_plls;
335
336	for (i = 0; i < nr_plls; ++i)
337		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
338
339	return ctx;
340}
341