xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rv1108.c (revision bae2f282a96e400a2bbcc8a545598289f36e1c32)
1*bae2f282SAndy Yan /*
2*bae2f282SAndy Yan  * (C) Copyright 2016 Rockchip Electronics Co., Ltd
3*bae2f282SAndy Yan  * Author: Andy Yan <andy.yan@rock-chips.com>
4*bae2f282SAndy Yan  * SPDX-License-Identifier:	GPL-2.0
5*bae2f282SAndy Yan  */
6*bae2f282SAndy Yan 
7*bae2f282SAndy Yan #include <common.h>
8*bae2f282SAndy Yan #include <clk-uclass.h>
9*bae2f282SAndy Yan #include <dm.h>
10*bae2f282SAndy Yan #include <errno.h>
11*bae2f282SAndy Yan #include <syscon.h>
12*bae2f282SAndy Yan #include <asm/io.h>
13*bae2f282SAndy Yan #include <asm/arch/clock.h>
14*bae2f282SAndy Yan #include <asm/arch/cru_rv1108.h>
15*bae2f282SAndy Yan #include <asm/arch/hardware.h>
16*bae2f282SAndy Yan #include <dm/lists.h>
17*bae2f282SAndy Yan #include <dt-bindings/clock/rv1108-cru.h>
18*bae2f282SAndy Yan 
19*bae2f282SAndy Yan DECLARE_GLOBAL_DATA_PTR;
20*bae2f282SAndy Yan 
21*bae2f282SAndy Yan enum {
22*bae2f282SAndy Yan 	VCO_MAX_HZ	= 2400U * 1000000,
23*bae2f282SAndy Yan 	VCO_MIN_HZ	= 600 * 1000000,
24*bae2f282SAndy Yan 	OUTPUT_MAX_HZ	= 2400U * 1000000,
25*bae2f282SAndy Yan 	OUTPUT_MIN_HZ	= 24 * 1000000,
26*bae2f282SAndy Yan };
27*bae2f282SAndy Yan 
28*bae2f282SAndy Yan #define RATE_TO_DIV(input_rate, output_rate) \
29*bae2f282SAndy Yan 	((input_rate) / (output_rate) - 1);
30*bae2f282SAndy Yan 
31*bae2f282SAndy Yan #define DIV_TO_RATE(input_rate, div)	((input_rate) / ((div) + 1))
32*bae2f282SAndy Yan 
33*bae2f282SAndy Yan #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
34*bae2f282SAndy Yan 	.refdiv = _refdiv,\
35*bae2f282SAndy Yan 	.fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
36*bae2f282SAndy Yan 	.postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\
37*bae2f282SAndy Yan 	_Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\
38*bae2f282SAndy Yan 			 OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\
39*bae2f282SAndy Yan 			 #hz "Hz cannot be hit with PLL "\
40*bae2f282SAndy Yan 			 "divisors on line " __stringify(__LINE__));
41*bae2f282SAndy Yan 
42*bae2f282SAndy Yan /* use interge mode*/
43*bae2f282SAndy Yan static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1);
44*bae2f282SAndy Yan static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1);
45*bae2f282SAndy Yan 
46*bae2f282SAndy Yan static inline int rv1108_pll_id(enum rk_clk_id clk_id)
47*bae2f282SAndy Yan {
48*bae2f282SAndy Yan 	int id = 0;
49*bae2f282SAndy Yan 
50*bae2f282SAndy Yan 	switch (clk_id) {
51*bae2f282SAndy Yan 	case CLK_ARM:
52*bae2f282SAndy Yan 	case CLK_DDR:
53*bae2f282SAndy Yan 		id = clk_id - 1;
54*bae2f282SAndy Yan 		break;
55*bae2f282SAndy Yan 	case CLK_GENERAL:
56*bae2f282SAndy Yan 		id = 2;
57*bae2f282SAndy Yan 		break;
58*bae2f282SAndy Yan 	default:
59*bae2f282SAndy Yan 		printf("invalid pll id:%d\n", clk_id);
60*bae2f282SAndy Yan 		id = -1;
61*bae2f282SAndy Yan 		break;
62*bae2f282SAndy Yan 	}
63*bae2f282SAndy Yan 
64*bae2f282SAndy Yan 	return id;
65*bae2f282SAndy Yan }
66*bae2f282SAndy Yan 
67*bae2f282SAndy Yan static uint32_t rkclk_pll_get_rate(struct rv1108_cru *cru,
68*bae2f282SAndy Yan 				   enum rk_clk_id clk_id)
69*bae2f282SAndy Yan {
70*bae2f282SAndy Yan 	uint32_t refdiv, fbdiv, postdiv1, postdiv2;
71*bae2f282SAndy Yan 	uint32_t con0, con1, con3;
72*bae2f282SAndy Yan 	int pll_id = rv1108_pll_id(clk_id);
73*bae2f282SAndy Yan 	struct rv1108_pll *pll = &cru->pll[pll_id];
74*bae2f282SAndy Yan 	uint32_t freq;
75*bae2f282SAndy Yan 
76*bae2f282SAndy Yan 	con3 = readl(&pll->con3);
77*bae2f282SAndy Yan 
78*bae2f282SAndy Yan 	if (con3 & WORK_MODE_MASK) {
79*bae2f282SAndy Yan 		con0 = readl(&pll->con0);
80*bae2f282SAndy Yan 		con1 = readl(&pll->con1);
81*bae2f282SAndy Yan 		fbdiv = (con0 >> FBDIV_SHIFT) & FBDIV_MASK;
82*bae2f282SAndy Yan 		postdiv1 = (con1 & POSTDIV1_MASK) >> POSTDIV1_SHIFT;
83*bae2f282SAndy Yan 		postdiv2 = (con1 & POSTDIV2_MASK) >> POSTDIV2_SHIFT;
84*bae2f282SAndy Yan 		refdiv = (con1 & REFDIV_MASK) >> REFDIV_SHIFT;
85*bae2f282SAndy Yan 		freq = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
86*bae2f282SAndy Yan 	} else {
87*bae2f282SAndy Yan 		freq = OSC_HZ;
88*bae2f282SAndy Yan 	}
89*bae2f282SAndy Yan 
90*bae2f282SAndy Yan 	return freq;
91*bae2f282SAndy Yan }
92*bae2f282SAndy Yan 
93*bae2f282SAndy Yan static int rv1108_mac_set_clk(struct rv1108_cru *cru, ulong rate)
94*bae2f282SAndy Yan {
95*bae2f282SAndy Yan 	uint32_t con = readl(&cru->clksel_con[24]);
96*bae2f282SAndy Yan 	ulong pll_rate;
97*bae2f282SAndy Yan 	uint8_t div;
98*bae2f282SAndy Yan 
99*bae2f282SAndy Yan 	if ((con >> MAC_PLL_SEL_SHIFT) & MAC_PLL_SEL_GPLL)
100*bae2f282SAndy Yan 		pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
101*bae2f282SAndy Yan 	else
102*bae2f282SAndy Yan 		pll_rate = rkclk_pll_get_rate(cru, CLK_ARM);
103*bae2f282SAndy Yan 
104*bae2f282SAndy Yan 	/*default set 50MHZ for gmac*/
105*bae2f282SAndy Yan 	if (!rate)
106*bae2f282SAndy Yan 		rate = 50000000;
107*bae2f282SAndy Yan 
108*bae2f282SAndy Yan 	div = DIV_ROUND_UP(pll_rate, rate) - 1;
109*bae2f282SAndy Yan 	if (div <= 0x1f)
110*bae2f282SAndy Yan 		rk_clrsetreg(&cru->clksel_con[24], MAC_CLK_DIV_MASK,
111*bae2f282SAndy Yan 			     div << MAC_CLK_DIV_SHIFT);
112*bae2f282SAndy Yan 	else
113*bae2f282SAndy Yan 		debug("Unsupported div for gmac:%d\n", div);
114*bae2f282SAndy Yan 
115*bae2f282SAndy Yan 	return DIV_TO_RATE(pll_rate, div);
116*bae2f282SAndy Yan }
117*bae2f282SAndy Yan 
118*bae2f282SAndy Yan static int rv1108_sfc_set_clk(struct rv1108_cru *cru, uint rate)
119*bae2f282SAndy Yan {
120*bae2f282SAndy Yan 	u32 con = readl(&cru->clksel_con[27]);
121*bae2f282SAndy Yan 	u32 pll_rate;
122*bae2f282SAndy Yan 	u32 div;
123*bae2f282SAndy Yan 
124*bae2f282SAndy Yan 	if ((con >> SFC_PLL_SEL_SHIFT) && SFC_PLL_SEL_GPLL)
125*bae2f282SAndy Yan 		pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
126*bae2f282SAndy Yan 	else
127*bae2f282SAndy Yan 		pll_rate = rkclk_pll_get_rate(cru, CLK_DDR);
128*bae2f282SAndy Yan 
129*bae2f282SAndy Yan 	div = DIV_ROUND_UP(pll_rate, rate) - 1;
130*bae2f282SAndy Yan 	if (div <= 0x3f)
131*bae2f282SAndy Yan 		rk_clrsetreg(&cru->clksel_con[27], SFC_CLK_DIV_MASK,
132*bae2f282SAndy Yan 			     div << SFC_CLK_DIV_SHIFT);
133*bae2f282SAndy Yan 	else
134*bae2f282SAndy Yan 		debug("Unsupported sfc clk rate:%d\n", rate);
135*bae2f282SAndy Yan 
136*bae2f282SAndy Yan 	return DIV_TO_RATE(pll_rate, div);
137*bae2f282SAndy Yan }
138*bae2f282SAndy Yan 
139*bae2f282SAndy Yan static ulong rv1108_clk_get_rate(struct clk *clk)
140*bae2f282SAndy Yan {
141*bae2f282SAndy Yan 	struct rv1108_clk_priv *priv = dev_get_priv(clk->dev);
142*bae2f282SAndy Yan 
143*bae2f282SAndy Yan 	switch (clk->id) {
144*bae2f282SAndy Yan 	case 0 ... 63:
145*bae2f282SAndy Yan 		return rkclk_pll_get_rate(priv->cru, clk->id);
146*bae2f282SAndy Yan 	default:
147*bae2f282SAndy Yan 		return -ENOENT;
148*bae2f282SAndy Yan 	}
149*bae2f282SAndy Yan }
150*bae2f282SAndy Yan 
151*bae2f282SAndy Yan static ulong rv1108_clk_set_rate(struct clk *clk, ulong rate)
152*bae2f282SAndy Yan {
153*bae2f282SAndy Yan 	struct rv1108_clk_priv *priv = dev_get_priv(clk->dev);
154*bae2f282SAndy Yan 	ulong new_rate;
155*bae2f282SAndy Yan 
156*bae2f282SAndy Yan 	switch (clk->id) {
157*bae2f282SAndy Yan 	case SCLK_MAC:
158*bae2f282SAndy Yan 		new_rate = rv1108_mac_set_clk(priv->cru, rate);
159*bae2f282SAndy Yan 		break;
160*bae2f282SAndy Yan 	case SCLK_SFC:
161*bae2f282SAndy Yan 		new_rate = rv1108_sfc_set_clk(priv->cru, rate);
162*bae2f282SAndy Yan 		break;
163*bae2f282SAndy Yan 	default:
164*bae2f282SAndy Yan 		return -ENOENT;
165*bae2f282SAndy Yan 	}
166*bae2f282SAndy Yan 
167*bae2f282SAndy Yan 	return new_rate;
168*bae2f282SAndy Yan }
169*bae2f282SAndy Yan 
170*bae2f282SAndy Yan static const struct clk_ops rv1108_clk_ops = {
171*bae2f282SAndy Yan 	.get_rate	= rv1108_clk_get_rate,
172*bae2f282SAndy Yan 	.set_rate	= rv1108_clk_set_rate,
173*bae2f282SAndy Yan };
174*bae2f282SAndy Yan 
175*bae2f282SAndy Yan static void rkclk_init(struct rv1108_cru *cru)
176*bae2f282SAndy Yan {
177*bae2f282SAndy Yan 	unsigned int apll = rkclk_pll_get_rate(cru, CLK_ARM);
178*bae2f282SAndy Yan 	unsigned int dpll = rkclk_pll_get_rate(cru, CLK_DDR);
179*bae2f282SAndy Yan 	unsigned int gpll = rkclk_pll_get_rate(cru, CLK_GENERAL);
180*bae2f282SAndy Yan 
181*bae2f282SAndy Yan 	rk_clrsetreg(&cru->clksel_con[0], CORE_CLK_DIV_MASK,
182*bae2f282SAndy Yan 		     0 << MAC_CLK_DIV_SHIFT);
183*bae2f282SAndy Yan 
184*bae2f282SAndy Yan 	printf("APLL: %d DPLL:%d GPLL:%d\n", apll, dpll, gpll);
185*bae2f282SAndy Yan }
186*bae2f282SAndy Yan 
187*bae2f282SAndy Yan static int rv1108_clk_probe(struct udevice *dev)
188*bae2f282SAndy Yan {
189*bae2f282SAndy Yan 	struct rv1108_clk_priv *priv = dev_get_priv(dev);
190*bae2f282SAndy Yan 
191*bae2f282SAndy Yan 	priv->cru = (struct rv1108_cru *)devfdt_get_addr(dev);
192*bae2f282SAndy Yan 
193*bae2f282SAndy Yan 	rkclk_init(priv->cru);
194*bae2f282SAndy Yan 
195*bae2f282SAndy Yan 	return 0;
196*bae2f282SAndy Yan }
197*bae2f282SAndy Yan 
198*bae2f282SAndy Yan static int rv1108_clk_bind(struct udevice *dev)
199*bae2f282SAndy Yan {
200*bae2f282SAndy Yan 	int ret;
201*bae2f282SAndy Yan 
202*bae2f282SAndy Yan 	/* The reset driver does not have a device node, so bind it here */
203*bae2f282SAndy Yan 	ret = device_bind_driver(gd->dm_root, "rv1108_sysreset", "reset", &dev);
204*bae2f282SAndy Yan 	if (ret)
205*bae2f282SAndy Yan 		error("No Rv1108 reset driver: ret=%d\n", ret);
206*bae2f282SAndy Yan 
207*bae2f282SAndy Yan 	return 0;
208*bae2f282SAndy Yan }
209*bae2f282SAndy Yan 
210*bae2f282SAndy Yan static const struct udevice_id rv1108_clk_ids[] = {
211*bae2f282SAndy Yan 	{ .compatible = "rockchip,rv1108-cru" },
212*bae2f282SAndy Yan 	{ }
213*bae2f282SAndy Yan };
214*bae2f282SAndy Yan 
215*bae2f282SAndy Yan U_BOOT_DRIVER(clk_rv1108) = {
216*bae2f282SAndy Yan 	.name		= "clk_rv1108",
217*bae2f282SAndy Yan 	.id		= UCLASS_CLK,
218*bae2f282SAndy Yan 	.of_match	= rv1108_clk_ids,
219*bae2f282SAndy Yan 	.priv_auto_alloc_size = sizeof(struct rv1108_clk_priv),
220*bae2f282SAndy Yan 	.ops		= &rv1108_clk_ops,
221*bae2f282SAndy Yan 	.bind		= rv1108_clk_bind,
222*bae2f282SAndy Yan 	.probe		= rv1108_clk_probe,
223*bae2f282SAndy Yan };
224