xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3368.c (revision d1dcf8527ececd1595d7ae6dc56c19bbcf0c537d)
1*d1dcf852SAndy Yan /*
2*d1dcf852SAndy Yan  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3*d1dcf852SAndy Yan  * Author: Andy Yan <andy.yan@rock-chips.com>
4*d1dcf852SAndy Yan  * SPDX-License-Identifier:	GPL-2.0
5*d1dcf852SAndy Yan  */
6*d1dcf852SAndy Yan 
7*d1dcf852SAndy Yan #include <common.h>
8*d1dcf852SAndy Yan #include <clk-uclass.h>
9*d1dcf852SAndy Yan #include <dm.h>
10*d1dcf852SAndy Yan #include <errno.h>
11*d1dcf852SAndy Yan #include <syscon.h>
12*d1dcf852SAndy Yan #include <asm/arch/clock.h>
13*d1dcf852SAndy Yan #include <asm/arch/cru_rk3368.h>
14*d1dcf852SAndy Yan #include <asm/arch/hardware.h>
15*d1dcf852SAndy Yan #include <asm/io.h>
16*d1dcf852SAndy Yan #include <dm/lists.h>
17*d1dcf852SAndy Yan #include <dt-bindings/clock/rk3368-cru.h>
18*d1dcf852SAndy Yan 
19*d1dcf852SAndy Yan DECLARE_GLOBAL_DATA_PTR;
20*d1dcf852SAndy Yan 
21*d1dcf852SAndy Yan struct pll_div {
22*d1dcf852SAndy Yan 	u32 nr;
23*d1dcf852SAndy Yan 	u32 nf;
24*d1dcf852SAndy Yan 	u32 no;
25*d1dcf852SAndy Yan };
26*d1dcf852SAndy Yan 
27*d1dcf852SAndy Yan #define OSC_HZ		(24 * 1000 * 1000)
28*d1dcf852SAndy Yan #define APLL_L_HZ	(800 * 1000 * 1000)
29*d1dcf852SAndy Yan #define APLL_B_HZ	(816 * 1000 * 1000)
30*d1dcf852SAndy Yan #define GPLL_HZ		(576 * 1000 * 1000)
31*d1dcf852SAndy Yan #define CPLL_HZ		(400 * 1000 * 1000)
32*d1dcf852SAndy Yan 
33*d1dcf852SAndy Yan #define RATE_TO_DIV(input_rate, output_rate) \
34*d1dcf852SAndy Yan 		((input_rate) / (output_rate) - 1);
35*d1dcf852SAndy Yan 
36*d1dcf852SAndy Yan #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
37*d1dcf852SAndy Yan 
38*d1dcf852SAndy Yan #define PLL_DIVISORS(hz, _nr, _no) { \
39*d1dcf852SAndy Yan 	.nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no}; \
40*d1dcf852SAndy Yan 	_Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\
41*d1dcf852SAndy Yan 		       (_nr * _no) == hz, #hz "Hz cannot be hit with PLL " \
42*d1dcf852SAndy Yan 		       "divisors on line " __stringify(__LINE__));
43*d1dcf852SAndy Yan 
44*d1dcf852SAndy Yan static const struct pll_div apll_l_init_cfg = PLL_DIVISORS(APLL_L_HZ, 12, 2);
45*d1dcf852SAndy Yan static const struct pll_div apll_b_init_cfg = PLL_DIVISORS(APLL_B_HZ, 1, 2);
46*d1dcf852SAndy Yan static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 2);
47*d1dcf852SAndy Yan static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 6);
48*d1dcf852SAndy Yan 
49*d1dcf852SAndy Yan /* Get pll rate by id */
50*d1dcf852SAndy Yan static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru,
51*d1dcf852SAndy Yan 				   enum rk3368_pll_id pll_id)
52*d1dcf852SAndy Yan {
53*d1dcf852SAndy Yan 	uint32_t nr, no, nf;
54*d1dcf852SAndy Yan 	uint32_t con;
55*d1dcf852SAndy Yan 	struct rk3368_pll *pll = &cru->pll[pll_id];
56*d1dcf852SAndy Yan 
57*d1dcf852SAndy Yan 	con = readl(&pll->con3);
58*d1dcf852SAndy Yan 
59*d1dcf852SAndy Yan 	switch ((con & PLL_MODE_MASK) >> PLL_MODE_SHIFT) {
60*d1dcf852SAndy Yan 	case PLL_MODE_SLOW:
61*d1dcf852SAndy Yan 		return OSC_HZ;
62*d1dcf852SAndy Yan 	case PLL_MODE_NORMAL:
63*d1dcf852SAndy Yan 		con = readl(&pll->con0);
64*d1dcf852SAndy Yan 		no = ((con & PLL_OD_MASK) >> PLL_OD_SHIFT) + 1;
65*d1dcf852SAndy Yan 		nr = ((con & PLL_NR_MASK) >> PLL_NR_SHIFT) + 1;
66*d1dcf852SAndy Yan 		con = readl(&pll->con1);
67*d1dcf852SAndy Yan 		nf = ((con & PLL_NF_MASK) >> PLL_NF_SHIFT) + 1;
68*d1dcf852SAndy Yan 
69*d1dcf852SAndy Yan 		return (24 * nf / (nr * no)) * 1000000;
70*d1dcf852SAndy Yan 	case PLL_MODE_DEEP_SLOW:
71*d1dcf852SAndy Yan 	default:
72*d1dcf852SAndy Yan 		return 32768;
73*d1dcf852SAndy Yan 	}
74*d1dcf852SAndy Yan }
75*d1dcf852SAndy Yan 
76*d1dcf852SAndy Yan static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id,
77*d1dcf852SAndy Yan 			 const struct pll_div *div, bool has_bwadj)
78*d1dcf852SAndy Yan {
79*d1dcf852SAndy Yan 	struct rk3368_pll *pll = &cru->pll[pll_id];
80*d1dcf852SAndy Yan 	/* All PLLs have same VCO and output frequency range restrictions*/
81*d1dcf852SAndy Yan 	uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000;
82*d1dcf852SAndy Yan 	uint output_hz = vco_hz / div->no;
83*d1dcf852SAndy Yan 
84*d1dcf852SAndy Yan 	debug("PLL at %p: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
85*d1dcf852SAndy Yan 	      pll, div->nf, div->nr, div->no, vco_hz, output_hz);
86*d1dcf852SAndy Yan 
87*d1dcf852SAndy Yan 	/* enter slow mode and reset pll */
88*d1dcf852SAndy Yan 	rk_clrsetreg(&pll->con3, PLL_MODE_MASK | PLL_RESET_MASK,
89*d1dcf852SAndy Yan 		     PLL_RESET << PLL_RESET_SHIFT);
90*d1dcf852SAndy Yan 
91*d1dcf852SAndy Yan 	rk_clrsetreg(&pll->con0, PLL_NR_MASK | PLL_OD_MASK,
92*d1dcf852SAndy Yan 		     ((div->nr - 1) << PLL_NR_SHIFT) |
93*d1dcf852SAndy Yan 		     ((div->no - 1) << PLL_OD_SHIFT));
94*d1dcf852SAndy Yan 	writel((div->nf - 1) << PLL_NF_SHIFT, &pll->con1);
95*d1dcf852SAndy Yan 	udelay(10);
96*d1dcf852SAndy Yan 
97*d1dcf852SAndy Yan 	/* return from reset */
98*d1dcf852SAndy Yan 	rk_clrreg(&pll->con3, PLL_RESET_MASK);
99*d1dcf852SAndy Yan 
100*d1dcf852SAndy Yan 	/* waiting for pll lock */
101*d1dcf852SAndy Yan 	while (!(readl(&pll->con1) & PLL_LOCK_STA))
102*d1dcf852SAndy Yan 		udelay(1);
103*d1dcf852SAndy Yan 
104*d1dcf852SAndy Yan 	rk_clrsetreg(&pll->con3, PLL_MODE_MASK,
105*d1dcf852SAndy Yan 		     PLL_MODE_NORMAL << PLL_MODE_SHIFT);
106*d1dcf852SAndy Yan 
107*d1dcf852SAndy Yan 	return 0;
108*d1dcf852SAndy Yan }
109*d1dcf852SAndy Yan 
110*d1dcf852SAndy Yan static void rkclk_init(struct rk3368_cru *cru)
111*d1dcf852SAndy Yan {
112*d1dcf852SAndy Yan 	u32 apllb, aplll, dpll, cpll, gpll;
113*d1dcf852SAndy Yan 
114*d1dcf852SAndy Yan 	rkclk_set_pll(cru, APLLB, &apll_b_init_cfg, false);
115*d1dcf852SAndy Yan 	rkclk_set_pll(cru, APLLL, &apll_l_init_cfg, false);
116*d1dcf852SAndy Yan 	rkclk_set_pll(cru, GPLL, &gpll_init_cfg, false);
117*d1dcf852SAndy Yan 	rkclk_set_pll(cru, CPLL, &cpll_init_cfg, false);
118*d1dcf852SAndy Yan 
119*d1dcf852SAndy Yan 	apllb = rkclk_pll_get_rate(cru, APLLB);
120*d1dcf852SAndy Yan 	aplll = rkclk_pll_get_rate(cru, APLLL);
121*d1dcf852SAndy Yan 	dpll = rkclk_pll_get_rate(cru, DPLL);
122*d1dcf852SAndy Yan 	cpll = rkclk_pll_get_rate(cru, CPLL);
123*d1dcf852SAndy Yan 	gpll = rkclk_pll_get_rate(cru, GPLL);
124*d1dcf852SAndy Yan 
125*d1dcf852SAndy Yan 	debug("%s apllb(%d) apll(%d) dpll(%d) cpll(%d) gpll(%d)\n",
126*d1dcf852SAndy Yan 	       __func__, apllb, aplll, dpll, cpll, gpll);
127*d1dcf852SAndy Yan }
128*d1dcf852SAndy Yan 
129*d1dcf852SAndy Yan static ulong rk3368_mmc_get_clk(struct rk3368_cru *cru, uint clk_id)
130*d1dcf852SAndy Yan {
131*d1dcf852SAndy Yan 	u32 div, con, con_id, rate;
132*d1dcf852SAndy Yan 	u32 pll_rate;
133*d1dcf852SAndy Yan 
134*d1dcf852SAndy Yan 	switch (clk_id) {
135*d1dcf852SAndy Yan 	case SCLK_SDMMC:
136*d1dcf852SAndy Yan 		con_id = 50;
137*d1dcf852SAndy Yan 		break;
138*d1dcf852SAndy Yan 	case SCLK_EMMC:
139*d1dcf852SAndy Yan 		con_id = 51;
140*d1dcf852SAndy Yan 		break;
141*d1dcf852SAndy Yan 	case SCLK_SDIO0:
142*d1dcf852SAndy Yan 		con_id = 48;
143*d1dcf852SAndy Yan 		break;
144*d1dcf852SAndy Yan 	default:
145*d1dcf852SAndy Yan 		return -EINVAL;
146*d1dcf852SAndy Yan 	}
147*d1dcf852SAndy Yan 
148*d1dcf852SAndy Yan 	con = readl(&cru->clksel_con[con_id]);
149*d1dcf852SAndy Yan 	switch ((con & MMC_PLL_SEL_MASK) >> MMC_PLL_SEL_SHIFT) {
150*d1dcf852SAndy Yan 	case MMC_PLL_SEL_GPLL:
151*d1dcf852SAndy Yan 		pll_rate = rkclk_pll_get_rate(cru, GPLL);
152*d1dcf852SAndy Yan 		break;
153*d1dcf852SAndy Yan 	case MMC_PLL_SEL_24M:
154*d1dcf852SAndy Yan 		pll_rate = OSC_HZ;
155*d1dcf852SAndy Yan 		break;
156*d1dcf852SAndy Yan 	case MMC_PLL_SEL_CPLL:
157*d1dcf852SAndy Yan 	case MMC_PLL_SEL_USBPHY_480M:
158*d1dcf852SAndy Yan 	default:
159*d1dcf852SAndy Yan 		return -EINVAL;
160*d1dcf852SAndy Yan 	}
161*d1dcf852SAndy Yan 	div = (con & MMC_CLK_DIV_MASK) >> MMC_CLK_DIV_SHIFT;
162*d1dcf852SAndy Yan 	rate = DIV_TO_RATE(pll_rate, div);
163*d1dcf852SAndy Yan 
164*d1dcf852SAndy Yan 	return rate >> 1;
165*d1dcf852SAndy Yan }
166*d1dcf852SAndy Yan 
167*d1dcf852SAndy Yan static ulong rk3368_mmc_set_clk(struct rk3368_cru *cru,
168*d1dcf852SAndy Yan 				ulong clk_id, ulong rate)
169*d1dcf852SAndy Yan {
170*d1dcf852SAndy Yan 	u32 div;
171*d1dcf852SAndy Yan 	u32 con_id;
172*d1dcf852SAndy Yan 	u32 gpll_rate = rkclk_pll_get_rate(cru, GPLL);
173*d1dcf852SAndy Yan 
174*d1dcf852SAndy Yan 	div = RATE_TO_DIV(gpll_rate, rate << 1);
175*d1dcf852SAndy Yan 
176*d1dcf852SAndy Yan 	switch (clk_id) {
177*d1dcf852SAndy Yan 	case SCLK_SDMMC:
178*d1dcf852SAndy Yan 		con_id = 50;
179*d1dcf852SAndy Yan 		break;
180*d1dcf852SAndy Yan 	case SCLK_EMMC:
181*d1dcf852SAndy Yan 		con_id = 51;
182*d1dcf852SAndy Yan 		break;
183*d1dcf852SAndy Yan 	case SCLK_SDIO0:
184*d1dcf852SAndy Yan 		con_id = 48;
185*d1dcf852SAndy Yan 		break;
186*d1dcf852SAndy Yan 	default:
187*d1dcf852SAndy Yan 		return -EINVAL;
188*d1dcf852SAndy Yan 	}
189*d1dcf852SAndy Yan 
190*d1dcf852SAndy Yan 	if (div > 0x3f) {
191*d1dcf852SAndy Yan 		div = RATE_TO_DIV(OSC_HZ, rate);
192*d1dcf852SAndy Yan 		rk_clrsetreg(&cru->clksel_con[con_id],
193*d1dcf852SAndy Yan 			     MMC_PLL_SEL_MASK | MMC_CLK_DIV_MASK,
194*d1dcf852SAndy Yan 			     (MMC_PLL_SEL_24M << MMC_PLL_SEL_SHIFT) |
195*d1dcf852SAndy Yan 			     (div << MMC_CLK_DIV_SHIFT));
196*d1dcf852SAndy Yan 	} else {
197*d1dcf852SAndy Yan 		rk_clrsetreg(&cru->clksel_con[con_id],
198*d1dcf852SAndy Yan 			     MMC_PLL_SEL_MASK | MMC_CLK_DIV_MASK,
199*d1dcf852SAndy Yan 			     (MMC_PLL_SEL_GPLL << MMC_PLL_SEL_SHIFT) |
200*d1dcf852SAndy Yan 			     div << MMC_CLK_DIV_SHIFT);
201*d1dcf852SAndy Yan 	}
202*d1dcf852SAndy Yan 
203*d1dcf852SAndy Yan 	return rk3368_mmc_get_clk(cru, clk_id);
204*d1dcf852SAndy Yan }
205*d1dcf852SAndy Yan 
206*d1dcf852SAndy Yan static ulong rk3368_clk_get_rate(struct clk *clk)
207*d1dcf852SAndy Yan {
208*d1dcf852SAndy Yan 	struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
209*d1dcf852SAndy Yan 	ulong rate = 0;
210*d1dcf852SAndy Yan 
211*d1dcf852SAndy Yan 	debug("%s id:%ld\n", __func__, clk->id);
212*d1dcf852SAndy Yan 	switch (clk->id) {
213*d1dcf852SAndy Yan 	case HCLK_SDMMC:
214*d1dcf852SAndy Yan 	case HCLK_EMMC:
215*d1dcf852SAndy Yan 		rate = rk3368_mmc_get_clk(priv->cru, clk->id);
216*d1dcf852SAndy Yan 		break;
217*d1dcf852SAndy Yan 	default:
218*d1dcf852SAndy Yan 		return -ENOENT;
219*d1dcf852SAndy Yan 	}
220*d1dcf852SAndy Yan 
221*d1dcf852SAndy Yan 	return rate;
222*d1dcf852SAndy Yan }
223*d1dcf852SAndy Yan 
224*d1dcf852SAndy Yan static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate)
225*d1dcf852SAndy Yan {
226*d1dcf852SAndy Yan 	struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
227*d1dcf852SAndy Yan 	ulong ret = 0;
228*d1dcf852SAndy Yan 
229*d1dcf852SAndy Yan 	debug("%s id:%ld rate:%ld\n", __func__, clk->id, rate);
230*d1dcf852SAndy Yan 	switch (clk->id) {
231*d1dcf852SAndy Yan 	case SCLK_SDMMC:
232*d1dcf852SAndy Yan 	case SCLK_EMMC:
233*d1dcf852SAndy Yan 		ret = rk3368_mmc_set_clk(priv->cru, clk->id, rate);
234*d1dcf852SAndy Yan 		break;
235*d1dcf852SAndy Yan 	default:
236*d1dcf852SAndy Yan 		return -ENOENT;
237*d1dcf852SAndy Yan 	}
238*d1dcf852SAndy Yan 
239*d1dcf852SAndy Yan 	return ret;
240*d1dcf852SAndy Yan }
241*d1dcf852SAndy Yan 
242*d1dcf852SAndy Yan static struct clk_ops rk3368_clk_ops = {
243*d1dcf852SAndy Yan 	.get_rate = rk3368_clk_get_rate,
244*d1dcf852SAndy Yan 	.set_rate = rk3368_clk_set_rate,
245*d1dcf852SAndy Yan };
246*d1dcf852SAndy Yan 
247*d1dcf852SAndy Yan static int rk3368_clk_probe(struct udevice *dev)
248*d1dcf852SAndy Yan {
249*d1dcf852SAndy Yan 	struct rk3368_clk_priv *priv = dev_get_priv(dev);
250*d1dcf852SAndy Yan 
251*d1dcf852SAndy Yan 	rkclk_init(priv->cru);
252*d1dcf852SAndy Yan 
253*d1dcf852SAndy Yan 	return 0;
254*d1dcf852SAndy Yan }
255*d1dcf852SAndy Yan 
256*d1dcf852SAndy Yan static int rk3368_clk_ofdata_to_platdata(struct udevice *dev)
257*d1dcf852SAndy Yan {
258*d1dcf852SAndy Yan 	struct rk3368_clk_priv *priv = dev_get_priv(dev);
259*d1dcf852SAndy Yan 
260*d1dcf852SAndy Yan 	priv->cru = (struct rk3368_cru *)devfdt_get_addr(dev);
261*d1dcf852SAndy Yan 
262*d1dcf852SAndy Yan 	return 0;
263*d1dcf852SAndy Yan }
264*d1dcf852SAndy Yan 
265*d1dcf852SAndy Yan static int rk3368_clk_bind(struct udevice *dev)
266*d1dcf852SAndy Yan {
267*d1dcf852SAndy Yan 	int ret;
268*d1dcf852SAndy Yan 
269*d1dcf852SAndy Yan 	/* The reset driver does not have a device node, so bind it here */
270*d1dcf852SAndy Yan 	ret = device_bind_driver(gd->dm_root, "rk3368_sysreset", "reset", &dev);
271*d1dcf852SAndy Yan 	if (ret)
272*d1dcf852SAndy Yan 		error("bind RK3368 reset driver failed: ret=%d\n", ret);
273*d1dcf852SAndy Yan 
274*d1dcf852SAndy Yan 	return ret;
275*d1dcf852SAndy Yan }
276*d1dcf852SAndy Yan 
277*d1dcf852SAndy Yan static const struct udevice_id rk3368_clk_ids[] = {
278*d1dcf852SAndy Yan 	{ .compatible = "rockchip,rk3368-cru" },
279*d1dcf852SAndy Yan 	{ }
280*d1dcf852SAndy Yan };
281*d1dcf852SAndy Yan 
282*d1dcf852SAndy Yan U_BOOT_DRIVER(rockchip_rk3368_cru) = {
283*d1dcf852SAndy Yan 	.name		= "rockchip_rk3368_cru",
284*d1dcf852SAndy Yan 	.id		= UCLASS_CLK,
285*d1dcf852SAndy Yan 	.of_match	= rk3368_clk_ids,
286*d1dcf852SAndy Yan 	.priv_auto_alloc_size = sizeof(struct rk3368_cru),
287*d1dcf852SAndy Yan 	.ofdata_to_platdata = rk3368_clk_ofdata_to_platdata,
288*d1dcf852SAndy Yan 	.ops		= &rk3368_clk_ops,
289*d1dcf852SAndy Yan 	.bind		= rk3368_clk_bind,
290*d1dcf852SAndy Yan 	.probe		= rk3368_clk_probe,
291*d1dcf852SAndy Yan };
292