1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com>
4 * (C) Copyright 2018 - BayLibre, SAS
5 * Author: Neil Armstrong <narmstrong@baylibre.com>
6 */
7
8#include <common.h>
9#include <log.h>
10#include <asm/arch/clock-g12a.h>
11#include <asm/io.h>
12#include <clk-uclass.h>
13#include <dm.h>
14#include <regmap.h>
15#include <syscon.h>
16#include <div64.h>
17#include <dt-bindings/clock/g12a-clkc.h>
18#include <linux/bitops.h>
19#include <linux/delay.h>
20#include <linux/err.h>
21#include <linux/kernel.h>
22#include "clk_meson.h"
23
24/* This driver support only basic clock tree operations :
25 * - Can calculate clock frequency on a limited tree
26 * - Can Read muxes and basic dividers (0-based only)
27 * - Can enable/disable gates with limited propagation
28 * - Can reparent without propagation, only on muxes
29 * - Can set rates without reparenting
30 * This driver is adapted to what is actually supported by U-Boot
31 */
32
33/* Only the clocks ids we don't want to expose, such as the internal muxes
34 * and dividers of composite clocks, will remain defined here.
35 */
36#define CLKID_MPEG_SEL				8
37#define CLKID_MPEG_DIV				9
38#define CLKID_SD_EMMC_A_CLK0_SEL		63
39#define CLKID_SD_EMMC_A_CLK0_DIV		64
40#define CLKID_SD_EMMC_B_CLK0_SEL		65
41#define CLKID_SD_EMMC_B_CLK0_DIV		66
42#define CLKID_SD_EMMC_C_CLK0_SEL		67
43#define CLKID_SD_EMMC_C_CLK0_DIV		68
44#define CLKID_MPLL0_DIV				69
45#define CLKID_MPLL1_DIV				70
46#define CLKID_MPLL2_DIV				71
47#define CLKID_MPLL3_DIV				72
48#define CLKID_MPLL_PREDIV			73
49#define CLKID_FCLK_DIV2_DIV			75
50#define CLKID_FCLK_DIV3_DIV			76
51#define CLKID_FCLK_DIV4_DIV			77
52#define CLKID_FCLK_DIV5_DIV			78
53#define CLKID_FCLK_DIV7_DIV			79
54#define CLKID_FCLK_DIV2P5_DIV			100
55#define CLKID_FIXED_PLL_DCO			101
56#define CLKID_SYS_PLL_DCO			102
57#define CLKID_GP0_PLL_DCO			103
58#define CLKID_HIFI_PLL_DCO			104
59#define CLKID_VPU_0_DIV				111
60#define CLKID_VPU_1_DIV				114
61#define CLKID_VAPB_0_DIV			118
62#define CLKID_VAPB_1_DIV			121
63#define CLKID_HDMI_PLL_DCO			125
64#define CLKID_HDMI_PLL_OD			126
65#define CLKID_HDMI_PLL_OD2			127
66#define CLKID_VID_PLL_SEL			130
67#define CLKID_VID_PLL_DIV			131
68#define CLKID_VCLK_SEL				132
69#define CLKID_VCLK2_SEL				133
70#define CLKID_VCLK_INPUT			134
71#define CLKID_VCLK2_INPUT			135
72#define CLKID_VCLK_DIV				136
73#define CLKID_VCLK2_DIV				137
74#define CLKID_VCLK_DIV2_EN			140
75#define CLKID_VCLK_DIV4_EN			141
76#define CLKID_VCLK_DIV6_EN			142
77#define CLKID_VCLK_DIV12_EN			143
78#define CLKID_VCLK2_DIV2_EN			144
79#define CLKID_VCLK2_DIV4_EN			145
80#define CLKID_VCLK2_DIV6_EN			146
81#define CLKID_VCLK2_DIV12_EN			147
82#define CLKID_CTS_ENCI_SEL			158
83#define CLKID_CTS_ENCP_SEL			159
84#define CLKID_CTS_VDAC_SEL			160
85#define CLKID_HDMI_TX_SEL			161
86#define CLKID_HDMI_SEL				166
87#define CLKID_HDMI_DIV				167
88#define CLKID_MALI_0_DIV			170
89#define CLKID_MALI_1_DIV			173
90
91#define CLKID_XTAL				0x10000000
92
93#define XTAL_RATE 24000000
94
95struct meson_clk {
96	struct regmap *map;
97};
98
99static ulong meson_div_get_rate(struct clk *clk, unsigned long id);
100static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate,
101				ulong current_rate);
102static ulong meson_mux_set_parent(struct clk *clk, unsigned long id,
103				  unsigned long parent_id);
104static ulong meson_mux_get_rate(struct clk *clk, unsigned long id);
105static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
106				      ulong rate, ulong current_rate);
107static ulong meson_mux_get_parent(struct clk *clk, unsigned long id);
108static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id);
109
110#define NUM_CLKS 178
111
112static struct meson_gate gates[NUM_CLKS] = {
113	/* Everything Else (EE) domain gates */
114	MESON_GATE(CLKID_SPICC0, HHI_GCLK_MPEG0, 8),
115	MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9),
116	MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13),
117	MESON_GATE(CLKID_SPICC1, HHI_GCLK_MPEG0, 14),
118	MESON_GATE(CLKID_SD_EMMC_A, HHI_GCLK_MPEG0, 4),
119	MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25),
120	MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26),
121	MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3),
122	MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16),
123	MESON_GATE(CLKID_PCIE_COMB, HHI_GCLK_MPEG1, 24),
124	MESON_GATE(CLKID_USB, HHI_GCLK_MPEG1, 25),
125	MESON_GATE(CLKID_PCIE_PHY, HHI_GCLK_MPEG1, 27),
126	MESON_GATE(CLKID_HTX_PCLK, HHI_GCLK_MPEG2, 4),
127	MESON_GATE(CLKID_USB1_DDR_BRIDGE, HHI_GCLK_MPEG2, 8),
128	MESON_GATE(CLKID_VPU_INTR, HHI_GCLK_MPEG2, 25),
129
130	/* Peripheral Gates */
131	MESON_GATE(CLKID_FCLK_DIV2, HHI_FIX_PLL_CNTL1, 24),
132	MESON_GATE(CLKID_FCLK_DIV3, HHI_FIX_PLL_CNTL1, 20),
133	MESON_GATE(CLKID_FCLK_DIV4, HHI_FIX_PLL_CNTL1, 21),
134	MESON_GATE(CLKID_FCLK_DIV5, HHI_FIX_PLL_CNTL1, 22),
135	MESON_GATE(CLKID_FCLK_DIV7, HHI_FIX_PLL_CNTL1, 23),
136	MESON_GATE(CLKID_SD_EMMC_A_CLK0, HHI_SD_EMMC_CLK_CNTL, 7),
137	MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23),
138	MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7),
139	MESON_GATE(CLKID_VPU_0, HHI_VPU_CLK_CNTL, 8),
140	MESON_GATE(CLKID_VPU_1, HHI_VPU_CLK_CNTL, 24),
141	MESON_GATE(CLKID_VAPB_0, HHI_VAPBCLK_CNTL, 8),
142	MESON_GATE(CLKID_VAPB_1, HHI_VAPBCLK_CNTL, 24),
143	MESON_GATE(CLKID_VAPB, HHI_VAPBCLK_CNTL, 30),
144	MESON_GATE(CLKID_HDMI, HHI_HDMI_CLK_CNTL, 8),
145};
146
147static int meson_set_gate_by_id(struct clk *clk, unsigned long id, bool on)
148{
149	struct meson_clk *priv = dev_get_priv(clk->dev);
150	struct meson_gate *gate;
151
152	debug("%s: %sabling %ld\n", __func__, on ? "en" : "dis", id);
153
154	/* Propagate through muxes */
155	switch (id) {
156	case CLKID_VPU:
157		return meson_set_gate_by_id(clk,
158				meson_mux_get_parent(clk, CLKID_VPU), on);
159	case CLKID_VAPB_SEL:
160		return meson_set_gate_by_id(clk,
161				meson_mux_get_parent(clk, CLKID_VAPB_SEL), on);
162	}
163
164	if (id >= ARRAY_SIZE(gates))
165		return -ENOENT;
166
167	gate = &gates[id];
168
169	if (gate->reg == 0)
170		return 0;
171
172	debug("%s: really %sabling %ld\n", __func__, on ? "en" : "dis", id);
173
174	regmap_update_bits(priv->map, gate->reg,
175			   BIT(gate->bit), on ? BIT(gate->bit) : 0);
176
177	/* Propagate to next gate(s) */
178	switch (id) {
179	case CLKID_VAPB:
180		return meson_set_gate_by_id(clk, CLKID_VAPB_SEL, on);
181	case CLKID_VAPB_0:
182		return meson_set_gate_by_id(clk,
183			meson_mux_get_parent(clk, CLKID_VAPB_0_SEL), on);
184	case CLKID_VAPB_1:
185		return meson_set_gate_by_id(clk,
186			meson_mux_get_parent(clk, CLKID_VAPB_0_SEL), on);
187	case CLKID_VPU_0:
188		return meson_set_gate_by_id(clk,
189			meson_mux_get_parent(clk, CLKID_VPU_0_SEL), on);
190	case CLKID_VPU_1:
191		return meson_set_gate_by_id(clk,
192			meson_mux_get_parent(clk, CLKID_VPU_1_SEL), on);
193	}
194
195	return 0;
196}
197
198static int meson_clk_enable(struct clk *clk)
199{
200	return meson_set_gate_by_id(clk, clk->id, true);
201}
202
203static int meson_clk_disable(struct clk *clk)
204{
205	return meson_set_gate_by_id(clk, clk->id, false);
206}
207
208static struct parm meson_vpu_0_div_parm = {
209	HHI_VPU_CLK_CNTL, 0, 7,
210};
211
212int meson_vpu_0_div_parent = CLKID_VPU_0_SEL;
213
214static struct parm meson_vpu_1_div_parm = {
215	HHI_VPU_CLK_CNTL, 16, 7,
216};
217
218int meson_vpu_1_div_parent = CLKID_VPU_1_SEL;
219
220static struct parm meson_vapb_0_div_parm = {
221	HHI_VAPBCLK_CNTL, 0, 7,
222};
223
224int meson_vapb_0_div_parent = CLKID_VAPB_0_SEL;
225
226static struct parm meson_vapb_1_div_parm = {
227	HHI_VAPBCLK_CNTL, 16, 7,
228};
229
230int meson_vapb_1_div_parent = CLKID_VAPB_1_SEL;
231
232static struct parm meson_hdmi_div_parm = {
233	HHI_HDMI_CLK_CNTL, 0, 7,
234};
235
236int meson_hdmi_div_parent = CLKID_HDMI_SEL;
237
238static ulong meson_div_get_rate(struct clk *clk, unsigned long id)
239{
240	struct meson_clk *priv = dev_get_priv(clk->dev);
241	unsigned int rate, parent_rate;
242	struct parm *parm;
243	int parent;
244	uint reg;
245
246	switch (id) {
247	case CLKID_VPU_0_DIV:
248		parm = &meson_vpu_0_div_parm;
249		parent = meson_vpu_0_div_parent;
250		break;
251	case CLKID_VPU_1_DIV:
252		parm = &meson_vpu_1_div_parm;
253		parent = meson_vpu_1_div_parent;
254		break;
255	case CLKID_VAPB_0_DIV:
256		parm = &meson_vapb_0_div_parm;
257		parent = meson_vapb_0_div_parent;
258		break;
259	case CLKID_VAPB_1_DIV:
260		parm = &meson_vapb_1_div_parm;
261		parent = meson_vapb_1_div_parent;
262		break;
263	case CLKID_HDMI_DIV:
264		parm = &meson_hdmi_div_parm;
265		parent = meson_hdmi_div_parent;
266		break;
267	default:
268		return -ENOENT;
269	}
270
271	regmap_read(priv->map, parm->reg_off, &reg);
272	reg = PARM_GET(parm->width, parm->shift, reg);
273
274	debug("%s: div of %ld is %d\n", __func__, id, reg + 1);
275
276	parent_rate = meson_clk_get_rate_by_id(clk, parent);
277	if (IS_ERR_VALUE(parent_rate))
278		return parent_rate;
279
280	debug("%s: parent rate of %ld is %d\n", __func__, id, parent_rate);
281
282	rate = parent_rate / (reg + 1);
283
284	debug("%s: rate of %ld is %d\n", __func__, id, rate);
285
286	return rate;
287}
288
289static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate,
290				ulong current_rate)
291{
292	struct meson_clk *priv = dev_get_priv(clk->dev);
293	unsigned int new_div = -EINVAL;
294	unsigned long parent_rate;
295	struct parm *parm;
296	int parent;
297	int ret;
298
299	if (current_rate == rate)
300		return 0;
301
302	debug("%s: setting rate of %ld from %ld to %ld\n",
303	      __func__, id, current_rate, rate);
304
305	switch (id) {
306	case CLKID_VPU_0_DIV:
307		parm = &meson_vpu_0_div_parm;
308		parent = meson_vpu_0_div_parent;
309		break;
310	case CLKID_VPU_1_DIV:
311		parm = &meson_vpu_1_div_parm;
312		parent = meson_vpu_1_div_parent;
313		break;
314	case CLKID_VAPB_0_DIV:
315		parm = &meson_vapb_0_div_parm;
316		parent = meson_vapb_0_div_parent;
317		break;
318	case CLKID_VAPB_1_DIV:
319		parm = &meson_vapb_1_div_parm;
320		parent = meson_vapb_1_div_parent;
321		break;
322	case CLKID_HDMI_DIV:
323		parm = &meson_hdmi_div_parm;
324		parent = meson_hdmi_div_parent;
325		break;
326	default:
327		return -ENOENT;
328	}
329
330	parent_rate = meson_clk_get_rate_by_id(clk, parent);
331	if (IS_ERR_VALUE(parent_rate))
332		return parent_rate;
333
334	debug("%s: parent rate of %ld is %ld\n", __func__, id, parent_rate);
335
336	/* If can't divide, set parent instead */
337	if (!parent_rate || rate > parent_rate)
338		return meson_clk_set_rate_by_id(clk, parent, rate,
339						current_rate);
340
341	new_div = DIV_ROUND_CLOSEST(parent_rate, rate);
342
343	debug("%s: new div of %ld is %d\n", __func__, id, new_div);
344
345	/* If overflow, try to set parent rate and retry */
346	if (!new_div || new_div > (1 << parm->width)) {
347		ret = meson_clk_set_rate_by_id(clk, parent, rate, current_rate);
348		if (IS_ERR_VALUE(ret))
349			return ret;
350
351		parent_rate = meson_clk_get_rate_by_id(clk, parent);
352		if (IS_ERR_VALUE(parent_rate))
353			return parent_rate;
354
355		new_div = DIV_ROUND_CLOSEST(parent_rate, rate);
356
357		debug("%s: new new div of %ld is %d\n", __func__, id, new_div);
358
359		if (!new_div || new_div > (1 << parm->width))
360			return -EINVAL;
361	}
362
363	debug("%s: setting div of %ld to %d\n", __func__, id, new_div);
364
365	regmap_update_bits(priv->map, parm->reg_off,
366			   SETPMASK(parm->width, parm->shift),
367			   (new_div - 1) << parm->shift);
368
369	debug("%s: new rate of %ld is %ld\n",
370	      __func__, id, meson_div_get_rate(clk, id));
371
372	return 0;
373}
374
375static struct parm meson_vpu_mux_parm = {
376	HHI_VPU_CLK_CNTL, 31, 1,
377};
378
379int meson_vpu_mux_parents[] = {
380	CLKID_VPU_0,
381	CLKID_VPU_1,
382};
383
384static struct parm meson_vpu_0_mux_parm = {
385	HHI_VPU_CLK_CNTL, 9, 3,
386};
387
388static struct parm meson_vpu_1_mux_parm = {
389	HHI_VPU_CLK_CNTL, 25, 3,
390};
391
392static int meson_vpu_0_1_mux_parents[] = {
393	CLKID_FCLK_DIV3,
394	CLKID_FCLK_DIV4,
395	CLKID_FCLK_DIV5,
396	CLKID_FCLK_DIV7,
397	-ENOENT,
398	-ENOENT,
399	-ENOENT,
400	-ENOENT,
401};
402
403static struct parm meson_vapb_sel_mux_parm = {
404	HHI_VAPBCLK_CNTL, 31, 1,
405};
406
407int meson_vapb_sel_mux_parents[] = {
408	CLKID_VAPB_0,
409	CLKID_VAPB_1,
410};
411
412static struct parm meson_vapb_0_mux_parm = {
413	HHI_VAPBCLK_CNTL, 9, 2,
414};
415
416static struct parm meson_vapb_1_mux_parm = {
417	HHI_VAPBCLK_CNTL, 25, 2,
418};
419
420static int meson_vapb_0_1_mux_parents[] = {
421	CLKID_FCLK_DIV4,
422	CLKID_FCLK_DIV3,
423	CLKID_FCLK_DIV5,
424	CLKID_FCLK_DIV7,
425};
426
427static struct parm meson_hdmi_mux_parm = {
428	HHI_HDMI_CLK_CNTL, 9, 2,
429};
430
431static int meson_hdmi_mux_parents[] = {
432	CLKID_XTAL,
433	CLKID_FCLK_DIV4,
434	CLKID_FCLK_DIV3,
435	CLKID_FCLK_DIV5,
436};
437
438static ulong meson_mux_get_parent(struct clk *clk, unsigned long id)
439{
440	struct meson_clk *priv = dev_get_priv(clk->dev);
441	struct parm *parm;
442	int *parents;
443	uint reg;
444
445	switch (id) {
446	case CLKID_VPU:
447		parm = &meson_vpu_mux_parm;
448		parents = meson_vpu_mux_parents;
449		break;
450	case CLKID_VPU_0_SEL:
451		parm = &meson_vpu_0_mux_parm;
452		parents = meson_vpu_0_1_mux_parents;
453		break;
454	case CLKID_VPU_1_SEL:
455		parm = &meson_vpu_1_mux_parm;
456		parents = meson_vpu_0_1_mux_parents;
457		break;
458	case CLKID_VAPB_SEL:
459		parm = &meson_vapb_sel_mux_parm;
460		parents = meson_vapb_sel_mux_parents;
461		break;
462	case CLKID_VAPB_0_SEL:
463		parm = &meson_vapb_0_mux_parm;
464		parents = meson_vapb_0_1_mux_parents;
465		break;
466	case CLKID_VAPB_1_SEL:
467		parm = &meson_vapb_1_mux_parm;
468		parents = meson_vapb_0_1_mux_parents;
469		break;
470	case CLKID_HDMI_SEL:
471		parm = &meson_hdmi_mux_parm;
472		parents = meson_hdmi_mux_parents;
473		break;
474	default:
475		return -ENOENT;
476	}
477
478	regmap_read(priv->map, parm->reg_off, &reg);
479	reg = PARM_GET(parm->width, parm->shift, reg);
480
481	debug("%s: parent of %ld is %d (%d)\n",
482	      __func__, id, parents[reg], reg);
483
484	return parents[reg];
485}
486
487static ulong meson_mux_set_parent(struct clk *clk, unsigned long id,
488				  unsigned long parent_id)
489{
490	unsigned long cur_parent = meson_mux_get_parent(clk, id);
491	struct meson_clk *priv = dev_get_priv(clk->dev);
492	unsigned int new_index = -EINVAL;
493	struct parm *parm;
494	int *parents;
495	int i;
496
497	if (IS_ERR_VALUE(cur_parent))
498		return cur_parent;
499
500	debug("%s: setting parent of %ld from %ld to %ld\n",
501	      __func__, id, cur_parent, parent_id);
502
503	if (cur_parent == parent_id)
504		return 0;
505
506	switch (id) {
507	case CLKID_VPU:
508		parm = &meson_vpu_mux_parm;
509		parents = meson_vpu_mux_parents;
510		break;
511	case CLKID_VPU_0_SEL:
512		parm = &meson_vpu_0_mux_parm;
513		parents = meson_vpu_0_1_mux_parents;
514		break;
515	case CLKID_VPU_1_SEL:
516		parm = &meson_vpu_1_mux_parm;
517		parents = meson_vpu_0_1_mux_parents;
518		break;
519	case CLKID_VAPB_SEL:
520		parm = &meson_vapb_sel_mux_parm;
521		parents = meson_vapb_sel_mux_parents;
522		break;
523	case CLKID_VAPB_0_SEL:
524		parm = &meson_vapb_0_mux_parm;
525		parents = meson_vapb_0_1_mux_parents;
526		break;
527	case CLKID_VAPB_1_SEL:
528		parm = &meson_vapb_1_mux_parm;
529		parents = meson_vapb_0_1_mux_parents;
530		break;
531	case CLKID_HDMI_SEL:
532		parm = &meson_hdmi_mux_parm;
533		parents = meson_hdmi_mux_parents;
534		break;
535	default:
536		/* Not a mux */
537		return -ENOENT;
538	}
539
540	for (i = 0 ; i < (1 << parm->width) ; ++i) {
541		if (parents[i] == parent_id)
542			new_index = i;
543	}
544
545	if (IS_ERR_VALUE(new_index))
546		return new_index;
547
548	debug("%s: new index of %ld is %d\n", __func__, id, new_index);
549
550	regmap_update_bits(priv->map, parm->reg_off,
551			   SETPMASK(parm->width, parm->shift),
552			   new_index << parm->shift);
553
554	debug("%s: new parent of %ld is %ld\n",
555	      __func__, id, meson_mux_get_parent(clk, id));
556
557	return 0;
558}
559
560static ulong meson_mux_get_rate(struct clk *clk, unsigned long id)
561{
562	int parent = meson_mux_get_parent(clk, id);
563
564	if (IS_ERR_VALUE(parent))
565		return parent;
566
567	return meson_clk_get_rate_by_id(clk, parent);
568}
569
570static unsigned long meson_clk81_get_rate(struct clk *clk)
571{
572	struct meson_clk *priv = dev_get_priv(clk->dev);
573	unsigned long parent_rate;
574	uint reg;
575	int parents[] = {
576		CLKID_XTAL,
577		-1,
578		CLKID_FCLK_DIV7,
579		CLKID_MPLL1,
580		CLKID_MPLL2,
581		CLKID_FCLK_DIV4,
582		CLKID_FCLK_DIV3,
583		CLKID_FCLK_DIV5
584	};
585
586	/* mux */
587	regmap_read(priv->map, HHI_MPEG_CLK_CNTL, &reg);
588	reg = (reg >> 12) & 7;
589
590	switch (reg) {
591	case 1:
592		return -ENOENT;
593	default:
594		parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]);
595	}
596
597	/* divider */
598	regmap_read(priv->map, HHI_MPEG_CLK_CNTL, &reg);
599	reg = reg & ((1 << 7) - 1);
600
601	return parent_rate / reg;
602}
603
604static long mpll_rate_from_params(unsigned long parent_rate,
605				  unsigned long sdm,
606				  unsigned long n2)
607{
608	unsigned long divisor = (SDM_DEN * n2) + sdm;
609
610	if (n2 < N2_MIN)
611		return -EINVAL;
612
613	return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor);
614}
615
616static struct parm meson_mpll0_parm[2] = {
617	{HHI_MPLL_CNTL1, 0, 14}, /* psdm */
618	{HHI_MPLL_CNTL1, 20, 9}, /* pn2 */
619};
620
621static struct parm meson_mpll1_parm[2] = {
622	{HHI_MPLL_CNTL3, 0, 14}, /* psdm */
623	{HHI_MPLL_CNTL3, 20, 9}, /* pn2 */
624};
625
626static struct parm meson_mpll2_parm[2] = {
627	{HHI_MPLL_CNTL5, 0, 14}, /* psdm */
628	{HHI_MPLL_CNTL5, 20, 9}, /* pn2 */
629};
630
631/*
632 * MultiPhase Locked Loops are outputs from a PLL with additional frequency
633 * scaling capabilities. MPLL rates are calculated as:
634 *
635 * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384)
636 */
637static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id)
638{
639	struct meson_clk *priv = dev_get_priv(clk->dev);
640	struct parm *psdm, *pn2;
641	unsigned long sdm, n2;
642	unsigned long parent_rate;
643	uint reg;
644
645	switch (id) {
646	case CLKID_MPLL0:
647		psdm = &meson_mpll0_parm[0];
648		pn2 = &meson_mpll0_parm[1];
649		break;
650	case CLKID_MPLL1:
651		psdm = &meson_mpll1_parm[0];
652		pn2 = &meson_mpll1_parm[1];
653		break;
654	case CLKID_MPLL2:
655		psdm = &meson_mpll2_parm[0];
656		pn2 = &meson_mpll2_parm[1];
657		break;
658	default:
659		return -ENOENT;
660	}
661
662	parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL);
663	if (IS_ERR_VALUE(parent_rate))
664		return parent_rate;
665
666	regmap_read(priv->map, psdm->reg_off, &reg);
667	sdm = PARM_GET(psdm->width, psdm->shift, reg);
668
669	regmap_read(priv->map, pn2->reg_off, &reg);
670	n2 = PARM_GET(pn2->width, pn2->shift, reg);
671
672	return mpll_rate_from_params(parent_rate, sdm, n2);
673}
674
675static struct parm meson_fixed_pll_parm[4] = {
676	{HHI_FIX_PLL_CNTL0, 0, 9}, /* pm */
677	{HHI_FIX_PLL_CNTL0, 10, 5}, /* pn */
678	{HHI_FIX_PLL_CNTL0, 16, 2}, /* pod */
679	{HHI_FIX_PLL_CNTL1, 0, 17}, /* pfrac */
680};
681
682static struct parm meson_sys_pll_parm[3] = {
683	{HHI_SYS_PLL_CNTL0, 0, 9}, /* pm */
684	{HHI_SYS_PLL_CNTL0, 10, 5}, /* pn */
685	{HHI_SYS_PLL_CNTL0, 16, 3}, /* pod */
686};
687
688static ulong meson_pll_get_rate(struct clk *clk, unsigned long id)
689{
690	struct meson_clk *priv = dev_get_priv(clk->dev);
691	struct parm *pm, *pn, *pod, *pfrac = NULL;
692	unsigned long parent_rate_mhz = XTAL_RATE / 1000000;
693	u16 n, m, od, frac;
694	ulong rate;
695	uint reg;
696
697	/*
698	 * FIXME: Between the unit conversion and the missing frac, we know
699	 * rate will be slightly off ...
700	*/
701
702	switch (id) {
703	case CLKID_FIXED_PLL:
704		pm = &meson_fixed_pll_parm[0];
705		pn = &meson_fixed_pll_parm[1];
706		pod = &meson_fixed_pll_parm[2];
707		pfrac = &meson_fixed_pll_parm[3];
708		break;
709	case CLKID_SYS_PLL:
710		pm = &meson_sys_pll_parm[0];
711		pn = &meson_sys_pll_parm[1];
712		pod = &meson_sys_pll_parm[2];
713		break;
714	default:
715		return -ENOENT;
716	}
717
718	regmap_read(priv->map, pn->reg_off, &reg);
719	n = PARM_GET(pn->width, pn->shift, reg);
720
721	regmap_read(priv->map, pm->reg_off, &reg);
722	m = PARM_GET(pm->width, pm->shift, reg);
723
724	regmap_read(priv->map, pod->reg_off, &reg);
725	od = PARM_GET(pod->width, pod->shift, reg);
726
727	rate = parent_rate_mhz * m;
728
729	if (pfrac) {
730		ulong frac_rate;
731
732		regmap_read(priv->map, pfrac->reg_off, &reg);
733		frac = PARM_GET(pfrac->width - 1, pfrac->shift, reg);
734
735		frac_rate = DIV_ROUND_UP_ULL((u64)parent_rate_mhz * frac,
736					     1 << (pfrac->width - 2));
737
738		if (frac & BIT(pfrac->width - 1))
739			rate -= frac_rate;
740		else
741			rate += frac_rate;
742	}
743
744	return (DIV_ROUND_UP_ULL(rate, n) >> od) * 1000000;
745}
746
747static struct parm meson_pcie_pll_parm[3] = {
748	{HHI_PCIE_PLL_CNTL0, 0, 8}, /* pm */
749	{HHI_PCIE_PLL_CNTL0, 10, 5}, /* pn */
750	{HHI_PCIE_PLL_CNTL0, 16, 5}, /* pod */
751};
752
753static ulong meson_pcie_pll_get_rate(struct clk *clk)
754{
755	struct meson_clk *priv = dev_get_priv(clk->dev);
756	struct parm *pm, *pn, *pod;
757	unsigned long parent_rate_mhz = XTAL_RATE / 1000000;
758	u16 n, m, od;
759	uint reg;
760
761	pm = &meson_pcie_pll_parm[0];
762	pn = &meson_pcie_pll_parm[1];
763	pod = &meson_pcie_pll_parm[2];
764
765	regmap_read(priv->map, pn->reg_off, &reg);
766	n = PARM_GET(pn->width, pn->shift, reg);
767
768	regmap_read(priv->map, pm->reg_off, &reg);
769	m = PARM_GET(pm->width, pm->shift, reg);
770
771	regmap_read(priv->map, pod->reg_off, &reg);
772	od = PARM_GET(pod->width, pod->shift, reg);
773
774	return ((parent_rate_mhz * m / n) / 2 / od / 2) * 1000000;
775}
776
777static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id)
778{
779	ulong rate;
780
781	switch (id) {
782	case CLKID_XTAL:
783		rate = XTAL_RATE;
784		break;
785	case CLKID_FIXED_PLL:
786	case CLKID_SYS_PLL:
787		rate = meson_pll_get_rate(clk, id);
788		break;
789	case CLKID_FCLK_DIV2:
790		rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2;
791		break;
792	case CLKID_FCLK_DIV3:
793		rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3;
794		break;
795	case CLKID_FCLK_DIV4:
796		rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4;
797		break;
798	case CLKID_FCLK_DIV5:
799		rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5;
800		break;
801	case CLKID_FCLK_DIV7:
802		rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7;
803		break;
804	case CLKID_MPLL0:
805	case CLKID_MPLL1:
806	case CLKID_MPLL2:
807		rate = meson_mpll_get_rate(clk, id);
808		break;
809	case CLKID_CLK81:
810		rate = meson_clk81_get_rate(clk);
811		break;
812	case CLKID_PCIE_PLL:
813		rate = meson_pcie_pll_get_rate(clk);
814		break;
815	case CLKID_VPU_0:
816		rate = meson_div_get_rate(clk, CLKID_VPU_0_DIV);
817		break;
818	case CLKID_VPU_1:
819		rate = meson_div_get_rate(clk, CLKID_VPU_1_DIV);
820		break;
821	case CLKID_VAPB:
822		rate = meson_mux_get_rate(clk, CLKID_VAPB_SEL);
823		break;
824	case CLKID_VAPB_0:
825		rate = meson_div_get_rate(clk, CLKID_VAPB_0_DIV);
826		break;
827	case CLKID_VAPB_1:
828		rate = meson_div_get_rate(clk, CLKID_VAPB_1_DIV);
829		break;
830	case CLKID_HDMI:
831		rate = meson_div_get_rate(clk, CLKID_HDMI_DIV);
832		break;
833	case CLKID_VPU_0_DIV:
834	case CLKID_VPU_1_DIV:
835	case CLKID_VAPB_0_DIV:
836	case CLKID_VAPB_1_DIV:
837	case CLKID_HDMI_DIV:
838		rate = meson_div_get_rate(clk, id);
839		break;
840	case CLKID_VPU:
841	case CLKID_VPU_0_SEL:
842	case CLKID_VPU_1_SEL:
843	case CLKID_VAPB_SEL:
844	case CLKID_VAPB_0_SEL:
845	case CLKID_VAPB_1_SEL:
846	case CLKID_HDMI_SEL:
847		rate = meson_mux_get_rate(clk, id);
848		break;
849	default:
850		if (gates[id].reg != 0) {
851			/* a clock gate */
852			rate = meson_clk81_get_rate(clk);
853			break;
854		}
855		return -ENOENT;
856	}
857
858	debug("clock %lu has rate %lu\n", id, rate);
859	return rate;
860}
861
862static ulong meson_clk_get_rate(struct clk *clk)
863{
864	return meson_clk_get_rate_by_id(clk, clk->id);
865}
866
867static ulong meson_pcie_pll_set_rate(struct clk *clk, ulong rate)
868{
869	struct meson_clk *priv = dev_get_priv(clk->dev);
870
871	regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x20090496);
872	regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x30090496);
873	regmap_write(priv->map, HHI_PCIE_PLL_CNTL1, 0x00000000);
874	regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001100);
875	regmap_write(priv->map, HHI_PCIE_PLL_CNTL3, 0x10058e00);
876	regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x000100c0);
877	regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000048);
878	regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000068);
879	udelay(20);
880	regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x008100c0);
881	udelay(10);
882	regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x34090496);
883	regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x14090496);
884	udelay(10);
885	regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001000);
886	regmap_update_bits(priv->map, HHI_PCIE_PLL_CNTL0,
887				0x1f << 16, 9 << 16);
888
889	return 100000000;
890}
891
892static int meson_clk_set_parent(struct clk *clk, struct clk *parent)
893{
894	return meson_mux_set_parent(clk, clk->id, parent->id);
895}
896
897static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
898				      ulong rate, ulong current_rate)
899{
900	if (current_rate == rate)
901		return 0;
902
903	switch (id) {
904	/* Fixed clocks */
905	case CLKID_FIXED_PLL:
906	case CLKID_SYS_PLL:
907	case CLKID_FCLK_DIV2:
908	case CLKID_FCLK_DIV3:
909	case CLKID_FCLK_DIV4:
910	case CLKID_FCLK_DIV5:
911	case CLKID_FCLK_DIV7:
912	case CLKID_MPLL0:
913	case CLKID_MPLL1:
914	case CLKID_MPLL2:
915	case CLKID_CLK81:
916		if (current_rate != rate)
917			return -EINVAL;
918	case CLKID_PCIE_PLL:
919		return meson_pcie_pll_set_rate(clk, rate);
920
921		return 0;
922	case CLKID_VPU:
923		return meson_clk_set_rate_by_id(clk,
924				meson_mux_get_parent(clk, CLKID_VPU), rate,
925						     current_rate);
926	case CLKID_VAPB:
927	case CLKID_VAPB_SEL:
928		return meson_clk_set_rate_by_id(clk,
929				meson_mux_get_parent(clk, CLKID_VAPB_SEL),
930				rate, current_rate);
931	case CLKID_VPU_0:
932		return meson_div_set_rate(clk, CLKID_VPU_0_DIV, rate,
933					  current_rate);
934	case CLKID_VPU_1:
935		return meson_div_set_rate(clk, CLKID_VPU_1_DIV, rate,
936					  current_rate);
937	case CLKID_VAPB_0:
938		return meson_div_set_rate(clk, CLKID_VAPB_0_DIV, rate,
939					  current_rate);
940	case CLKID_VAPB_1:
941		return meson_div_set_rate(clk, CLKID_VAPB_1_DIV, rate,
942					  current_rate);
943	case CLKID_VPU_0_DIV:
944	case CLKID_VPU_1_DIV:
945	case CLKID_VAPB_0_DIV:
946	case CLKID_VAPB_1_DIV:
947	case CLKID_HDMI_DIV:
948		return meson_div_set_rate(clk, id, rate, current_rate);
949	case CLKID_HDMI:
950		return meson_clk_set_rate_by_id(clk, CLKID_HDMI_DIV,
951						rate, current_rate);
952	default:
953		return -ENOENT;
954	}
955
956	return -EINVAL;
957}
958
959static ulong meson_clk_set_rate(struct clk *clk, ulong rate)
960{
961	ulong current_rate = meson_clk_get_rate_by_id(clk, clk->id);
962	int ret;
963
964	if (IS_ERR_VALUE(current_rate))
965		return current_rate;
966
967	debug("%s: setting rate of %ld from %ld to %ld\n",
968	      __func__, clk->id, current_rate, rate);
969
970	ret = meson_clk_set_rate_by_id(clk, clk->id, rate, current_rate);
971	if (IS_ERR_VALUE(ret))
972		return ret;
973
974	debug("clock %lu has new rate %lu\n", clk->id,
975	      meson_clk_get_rate_by_id(clk, clk->id));
976
977	return 0;
978}
979
980static int meson_clk_probe(struct udevice *dev)
981{
982	struct meson_clk *priv = dev_get_priv(dev);
983
984	priv->map = syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
985	if (IS_ERR(priv->map))
986		return PTR_ERR(priv->map);
987
988	/*
989	 * Depending on the boot src, the state of the MMC clock might
990	 * be different. Reset it to make sure we won't get stuck
991	 */
992	regmap_write(priv->map, HHI_NAND_CLK_CNTL, 0);
993	regmap_write(priv->map, HHI_SD_EMMC_CLK_CNTL, 0);
994
995	debug("meson-clk-g12a: probed\n");
996
997	return 0;
998}
999
1000static struct clk_ops meson_clk_ops = {
1001	.disable	= meson_clk_disable,
1002	.enable		= meson_clk_enable,
1003	.get_rate	= meson_clk_get_rate,
1004	.set_parent	= meson_clk_set_parent,
1005	.set_rate	= meson_clk_set_rate,
1006};
1007
1008static const struct udevice_id meson_clk_ids[] = {
1009	{ .compatible = "amlogic,g12a-clkc" },
1010	{ .compatible = "amlogic,g12b-clkc" },
1011	{ .compatible = "amlogic,sm1-clkc" },
1012	{ }
1013};
1014
1015U_BOOT_DRIVER(meson_clk_g12a) = {
1016	.name		= "meson_clk_g12a",
1017	.id		= UCLASS_CLK,
1018	.of_match	= meson_clk_ids,
1019	.priv_auto	= sizeof(struct meson_clk),
1020	.ops		= &meson_clk_ops,
1021	.probe		= meson_clk_probe,
1022};
1023