1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Main clock support for AT91 architectures.
4 *
5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
6 *
7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
8 *
9 * Based on drivers/clk/at91/clk-main.c from Linux.
10 */
11
12#include <asm/processor.h>
13#include <common.h>
14#include <clk-uclass.h>
15#include <dm.h>
16#include <linux/clk-provider.h>
17#include <linux/clk/at91_pmc.h>
18#include <linux/delay.h>
19#include <linux/io.h>
20#include <linux/time.h>
21#include "pmc.h"
22
23#define UBOOT_DM_CLK_AT91_MAIN_RC		"at91-main-rc-clk"
24#define UBOOT_DM_CLK_AT91_MAIN_OSC		"at91-main-osc-clk"
25#define UBOOT_DM_CLK_AT91_RM9200_MAIN		"at91-rm9200-main-clk"
26#define UBOOT_DM_CLK_AT91_SAM9X5_MAIN		"at91-sam9x5-main-clk"
27
28#define MOR_KEY_MASK		GENMASK(23, 16)
29#define SLOW_CLOCK_FREQ		32768
30
31#define clk_main_parent_select(s)	(((s) & \
32					(AT91_PMC_MOSCEN | \
33					AT91_PMC_OSCBYPASS)) ? 1 : 0)
34
35struct clk_main_rc {
36	void __iomem	*reg;
37	struct clk	clk;
38};
39
40#define to_clk_main_rc(_clk) container_of(_clk, struct clk_main_rc, clk)
41
42struct clk_main_osc {
43	void __iomem	*reg;
44	struct clk	clk;
45};
46
47#define to_clk_main_osc(_clk) container_of(_clk, struct clk_main_osc, clk)
48
49struct clk_main {
50	void __iomem		*reg;
51	const unsigned int	*clk_mux_table;
52	const char * const	*parent_names;
53	unsigned int		num_parents;
54	int			type;
55	struct clk		clk;
56};
57
58#define to_clk_main(_clk) container_of(_clk, struct clk_main, clk)
59
60static int main_rc_enable(struct clk *clk)
61{
62	struct clk_main_rc *main_rc = to_clk_main_rc(clk);
63	void __iomem *reg = main_rc->reg;
64	unsigned int val;
65
66	pmc_read(reg, AT91_CKGR_MOR, &val);
67
68	if (!(val & AT91_PMC_MOSCRCEN)) {
69		pmc_update_bits(reg, AT91_CKGR_MOR,
70				MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
71				AT91_PMC_KEY | AT91_PMC_MOSCRCEN);
72	}
73
74	pmc_read(reg, AT91_PMC_SR, &val);
75	while (!(val & AT91_PMC_MOSCRCS)) {
76		pmc_read(reg, AT91_PMC_SR, &val);
77		debug("waiting for main rc...\n");
78		cpu_relax();
79	}
80
81	return 0;
82}
83
84static int main_rc_disable(struct clk *clk)
85{
86	struct clk_main_rc *main_rc = to_clk_main_rc(clk);
87	struct reg *reg = main_rc->reg;
88	unsigned int val;
89
90	pmc_read(reg, AT91_CKGR_MOR, &val);
91
92	if (!(val & AT91_PMC_MOSCRCEN))
93		return 0;
94
95	pmc_update_bits(reg, AT91_CKGR_MOR, MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
96			AT91_PMC_KEY);
97
98	return 0;
99}
100
101static const struct clk_ops main_rc_clk_ops = {
102	.enable = main_rc_enable,
103	.disable = main_rc_disable,
104	.get_rate = clk_generic_get_rate,
105};
106
107struct clk *at91_clk_main_rc(void __iomem *reg, const char *name,
108			     const char *parent_name)
109{
110	struct clk_main_rc *main_rc;
111	struct clk *clk;
112	int ret;
113
114	if (!reg || !name || !parent_name)
115		return ERR_PTR(-EINVAL);
116
117	main_rc = kzalloc(sizeof(*main_rc), GFP_KERNEL);
118	if (!main_rc)
119		return ERR_PTR(-ENOMEM);
120
121	main_rc->reg = reg;
122	clk = &main_rc->clk;
123
124	ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_RC, name,
125			   parent_name);
126	if (ret) {
127		kfree(main_rc);
128		clk = ERR_PTR(ret);
129	}
130
131	return clk;
132}
133
134U_BOOT_DRIVER(at91_main_rc_clk) = {
135	.name = UBOOT_DM_CLK_AT91_MAIN_RC,
136	.id = UCLASS_CLK,
137	.ops = &main_rc_clk_ops,
138	.flags = DM_FLAG_PRE_RELOC,
139};
140
141static int clk_main_osc_enable(struct clk *clk)
142{
143	struct clk_main_osc *main = to_clk_main_osc(clk);
144	void __iomem *reg = main->reg;
145	unsigned int val;
146
147	pmc_read(reg, AT91_CKGR_MOR, &val);
148	val &= ~MOR_KEY_MASK;
149
150	if (val & AT91_PMC_OSCBYPASS)
151		return 0;
152
153	if (!(val & AT91_PMC_MOSCEN)) {
154		val |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
155		pmc_write(reg, AT91_CKGR_MOR, val);
156	}
157
158	pmc_read(reg, AT91_PMC_SR, &val);
159	while (!(val & AT91_PMC_MOSCS)) {
160		pmc_read(reg, AT91_PMC_SR, &val);
161		debug("waiting for main osc..\n");
162		cpu_relax();
163	}
164
165	return 0;
166}
167
168static int clk_main_osc_disable(struct clk *clk)
169{
170	struct clk_main_osc *main = to_clk_main_osc(clk);
171	void __iomem *reg = main->reg;
172	unsigned int val;
173
174	pmc_read(reg, AT91_CKGR_MOR, &val);
175	if (val & AT91_PMC_OSCBYPASS)
176		return 0;
177
178	if (!(val & AT91_PMC_MOSCEN))
179		return 0;
180
181	val &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
182	pmc_write(reg, AT91_CKGR_MOR, val | AT91_PMC_KEY);
183
184	return 0;
185}
186
187static const struct clk_ops main_osc_clk_ops = {
188	.enable = clk_main_osc_enable,
189	.disable = clk_main_osc_disable,
190	.get_rate = clk_generic_get_rate,
191};
192
193struct clk *at91_clk_main_osc(void __iomem *reg, const char *name,
194			      const char *parent_name, bool bypass)
195{
196	struct clk_main_osc *main;
197	struct clk *clk;
198	int ret;
199
200	if (!reg || !name || !parent_name)
201		return ERR_PTR(-EINVAL);
202
203	main = kzalloc(sizeof(*main), GFP_KERNEL);
204	if (!main)
205		return ERR_PTR(-ENOMEM);
206
207	main->reg = reg;
208	clk = &main->clk;
209
210	if (bypass) {
211		pmc_update_bits(reg, AT91_CKGR_MOR,
212				MOR_KEY_MASK | AT91_PMC_OSCBYPASS,
213				AT91_PMC_KEY | AT91_PMC_OSCBYPASS);
214	}
215
216	ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_OSC, name, parent_name);
217	if (ret) {
218		kfree(main);
219		clk = ERR_PTR(ret);
220	}
221
222	return clk;
223}
224
225U_BOOT_DRIVER(at91_main_osc_clk) = {
226	.name = UBOOT_DM_CLK_AT91_MAIN_OSC,
227	.id = UCLASS_CLK,
228	.ops = &main_osc_clk_ops,
229	.flags = DM_FLAG_PRE_RELOC,
230};
231
232static int clk_main_probe_frequency(void __iomem *reg)
233{
234	unsigned int cycles = 16;
235	unsigned int cycle = DIV_ROUND_UP(USEC_PER_SEC, SLOW_CLOCK_FREQ);
236	unsigned int mcfr;
237
238	while (cycles--) {
239		pmc_read(reg, AT91_CKGR_MCFR, &mcfr);
240		if (mcfr & AT91_PMC_MAINRDY)
241			return 0;
242		udelay(cycle);
243	}
244
245	return -ETIMEDOUT;
246}
247
248static int clk_rm9200_main_enable(struct clk *clk)
249{
250	struct clk_main *main = to_clk_main(clk);
251
252	return clk_main_probe_frequency(main->reg);
253}
254
255static const struct clk_ops rm9200_main_clk_ops = {
256	.enable = clk_rm9200_main_enable,
257};
258
259struct clk *at91_clk_rm9200_main(void __iomem *reg, const char *name,
260				 const char *parent_name)
261{
262	struct clk_main *main;
263	struct clk *clk;
264	int ret;
265
266	if (!reg || !name || !parent_name)
267		return ERR_PTR(-EINVAL);
268
269	main = kzalloc(sizeof(*main), GFP_KERNEL);
270	if (!main)
271		return ERR_PTR(-ENOMEM);
272
273	main->reg = reg;
274	clk = &main->clk;
275
276	ret = clk_register(clk, UBOOT_DM_CLK_AT91_RM9200_MAIN, name,
277			   parent_name);
278	if (ret) {
279		kfree(main);
280		clk = ERR_PTR(ret);
281	}
282
283	return clk;
284}
285
286U_BOOT_DRIVER(at91_rm9200_main_clk) = {
287	.name = UBOOT_DM_CLK_AT91_RM9200_MAIN,
288	.id = UCLASS_CLK,
289	.ops = &rm9200_main_clk_ops,
290	.flags = DM_FLAG_PRE_RELOC,
291};
292
293static inline bool clk_sam9x5_main_ready(void __iomem *reg)
294{
295	unsigned int val;
296
297	pmc_read(reg, AT91_PMC_SR, &val);
298
299	return !!(val & AT91_PMC_MOSCSELS);
300}
301
302static int clk_sam9x5_main_enable(struct clk *clk)
303{
304	struct clk_main *main = to_clk_main(clk);
305	void __iomem *reg = main->reg;
306
307	while (!clk_sam9x5_main_ready(reg)) {
308		debug("waiting for main...");
309		cpu_relax();
310	}
311
312	return clk_main_probe_frequency(reg);
313}
314
315static int clk_sam9x5_main_set_parent(struct clk *clk, struct clk *parent)
316{
317	struct clk_main *main = to_clk_main(clk);
318	void __iomem *reg = main->reg;
319	unsigned int tmp, index;
320
321	index = at91_clk_mux_val_to_index(main->clk_mux_table,
322			main->num_parents, AT91_CLK_ID_TO_DID(parent->id));
323	if (index < 0)
324		return index;
325
326	pmc_read(reg, AT91_CKGR_MOR, &tmp);
327	tmp &= ~MOR_KEY_MASK;
328	tmp |= AT91_PMC_KEY;
329
330	if (index && !(tmp & AT91_PMC_MOSCSEL))
331		pmc_write(reg, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
332	else if (!index && (tmp & AT91_PMC_MOSCSEL))
333		pmc_write(reg, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
334
335	while (!clk_sam9x5_main_ready(reg))
336		cpu_relax();
337
338	return 0;
339}
340
341static const struct clk_ops sam9x5_main_clk_ops = {
342	.enable = clk_sam9x5_main_enable,
343	.set_parent = clk_sam9x5_main_set_parent,
344	.get_rate = clk_generic_get_rate,
345};
346
347struct clk *at91_clk_sam9x5_main(void __iomem *reg, const char *name,
348				 const char * const *parent_names,
349				 int num_parents, const u32 *clk_mux_table,
350				 int type)
351{
352	struct clk *clk = ERR_PTR(-ENOMEM);
353	struct clk_main *main = NULL;
354	unsigned int val;
355	int ret;
356
357	if (!reg || !name || !parent_names || !num_parents || !clk_mux_table)
358		return ERR_PTR(-EINVAL);
359
360	main = kzalloc(sizeof(*main), GFP_KERNEL);
361	if (!main)
362		return ERR_PTR(-ENOMEM);
363
364	main->reg = reg;
365	main->parent_names = parent_names;
366	main->num_parents = num_parents;
367	main->clk_mux_table = clk_mux_table;
368	main->type = type;
369	clk = &main->clk;
370	clk->flags = CLK_GET_RATE_NOCACHE;
371	pmc_read(reg, AT91_CKGR_MOR, &val);
372	ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X5_MAIN, name,
373			   main->parent_names[clk_main_parent_select(val)]);
374	if (ret) {
375		kfree(main);
376		clk = ERR_PTR(ret);
377	}
378
379	return clk;
380}
381
382U_BOOT_DRIVER(at91_sam9x5_main_clk) = {
383	.name = UBOOT_DM_CLK_AT91_SAM9X5_MAIN,
384	.id = UCLASS_CLK,
385	.ops = &sam9x5_main_clk_ops,
386	.flags = DM_FLAG_PRE_RELOC,
387};
388