xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3399.c (revision 6cf98e2f9e382a696304b87680b0b4288e3080a5)
1aff8795cSHeiko Stübner /*
2aff8795cSHeiko Stübner  * (C) Copyright 2015 Google, Inc
38fa6979bSPhilipp Tomsich  * (C) 2017 Theobroma Systems Design und Consulting GmbH
4aff8795cSHeiko Stübner  *
5aff8795cSHeiko Stübner  * SPDX-License-Identifier:	GPL-2.0
6aff8795cSHeiko Stübner  */
7aff8795cSHeiko Stübner 
8aff8795cSHeiko Stübner #include <common.h>
9aff8795cSHeiko Stübner #include <clk-uclass.h>
10aff8795cSHeiko Stübner #include <dm.h>
115ae2fd97SKever Yang #include <dt-structs.h>
12aff8795cSHeiko Stübner #include <errno.h>
135ae2fd97SKever Yang #include <mapmem.h>
14aff8795cSHeiko Stübner #include <syscon.h>
15e78991bfSDavid Wu #include <bitfield.h>
16aff8795cSHeiko Stübner #include <asm/io.h>
17aff8795cSHeiko Stübner #include <asm/arch/clock.h>
18aff8795cSHeiko Stübner #include <asm/arch/cru_rk3399.h>
19aff8795cSHeiko Stübner #include <asm/arch/hardware.h>
20aff8795cSHeiko Stübner #include <dm/lists.h>
21aff8795cSHeiko Stübner #include <dt-bindings/clock/rk3399-cru.h>
22aff8795cSHeiko Stübner 
23aff8795cSHeiko Stübner DECLARE_GLOBAL_DATA_PTR;
24aff8795cSHeiko Stübner 
255ae2fd97SKever Yang #if CONFIG_IS_ENABLED(OF_PLATDATA)
265ae2fd97SKever Yang struct rk3399_clk_plat {
275ae2fd97SKever Yang 	struct dtd_rockchip_rk3399_cru dtd;
285e79f443SKever Yang };
295e79f443SKever Yang 
305ae2fd97SKever Yang struct rk3399_pmuclk_plat {
315ae2fd97SKever Yang 	struct dtd_rockchip_rk3399_pmucru dtd;
325ae2fd97SKever Yang };
335ae2fd97SKever Yang #endif
345ae2fd97SKever Yang 
35aff8795cSHeiko Stübner struct pll_div {
36aff8795cSHeiko Stübner 	u32 refdiv;
37aff8795cSHeiko Stübner 	u32 fbdiv;
38aff8795cSHeiko Stübner 	u32 postdiv1;
39aff8795cSHeiko Stübner 	u32 postdiv2;
40aff8795cSHeiko Stübner 	u32 frac;
41ccced9e1SLin Huang 	u32 freq;
42aff8795cSHeiko Stübner };
43aff8795cSHeiko Stübner 
44aff8795cSHeiko Stübner #define RATE_TO_DIV(input_rate, output_rate) \
45aff8795cSHeiko Stübner 	((input_rate) / (output_rate) - 1);
46aff8795cSHeiko Stübner #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
47aff8795cSHeiko Stübner 
48aff8795cSHeiko Stübner #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
49aff8795cSHeiko Stübner 	.refdiv = _refdiv,\
50aff8795cSHeiko Stübner 	.fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
51ccced9e1SLin Huang 	.postdiv1 = _postdiv1, .postdiv2 = _postdiv2, .freq = hz};
52aff8795cSHeiko Stübner 
531d2570d3SCaesar Wang #if !defined(CONFIG_SPL_BUILD)
54aff8795cSHeiko Stübner static const struct pll_div ppll_init_cfg = PLL_DIVISORS(PPLL_HZ, 2, 2, 1);
5561dff33bSPhilipp Tomsich #endif
5647b08574SKever Yang static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 3, 1);
574897499eSElaine Zhang static const struct pll_div npll_init_cfg = PLL_DIVISORS(NPLL_HZ, 1, 3, 1);
58ccced9e1SLin Huang static const struct pll_div apll_1600_cfg = PLL_DIVISORS(1600*MHz, 3, 1, 1);
598b75ff34SElaine Zhang static const struct pll_div apll_816_cfg = PLL_DIVISORS(816 * MHz, 1, 2, 1);
60ccced9e1SLin Huang static const struct pll_div apll_600_cfg = PLL_DIVISORS(600*MHz, 1, 2, 1);
61aff8795cSHeiko Stübner 
62ccced9e1SLin Huang static const struct pll_div *apll_cfgs[] = {
63ccced9e1SLin Huang 	[APLL_1600_MHZ] = &apll_1600_cfg,
648b75ff34SElaine Zhang 	[APLL_816_MHZ] = &apll_816_cfg,
65ccced9e1SLin Huang 	[APLL_600_MHZ] = &apll_600_cfg,
66aff8795cSHeiko Stübner };
67aff8795cSHeiko Stübner 
688b75ff34SElaine Zhang #ifndef CONFIG_SPL_BUILD
698b75ff34SElaine Zhang #define RK3399_CLK_DUMP(_id, _name, _iscru)    \
708b75ff34SElaine Zhang {                                              \
718b75ff34SElaine Zhang 	.id = _id,                              \
728b75ff34SElaine Zhang 	.name = _name,                          \
738b75ff34SElaine Zhang 	.is_cru = _iscru,                       \
748b75ff34SElaine Zhang }
758b75ff34SElaine Zhang 
768b75ff34SElaine Zhang static const struct rk3399_clk_info clks_dump[] = {
778b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PLL_APLLL, "aplll", true),
788b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PLL_APLLB, "apllb", true),
798b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PLL_DPLL, "dpll", true),
808b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PLL_CPLL, "cpll", true),
818b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PLL_GPLL, "gpll", true),
828b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PLL_NPLL, "npll", true),
838b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PLL_VPLL, "vpll", true),
848b75ff34SElaine Zhang 	RK3399_CLK_DUMP(ACLK_PERIHP, "aclk_perihp", true),
858b75ff34SElaine Zhang 	RK3399_CLK_DUMP(HCLK_PERIHP, "hclk_perihp", true),
868b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PCLK_PERIHP, "pclk_perihp", true),
878b75ff34SElaine Zhang 	RK3399_CLK_DUMP(ACLK_PERILP0, "aclk_perilp0", true),
888b75ff34SElaine Zhang 	RK3399_CLK_DUMP(HCLK_PERILP0, "hclk_perilp0", true),
898b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PCLK_PERILP0, "pclk_perilp0", true),
908b75ff34SElaine Zhang 	RK3399_CLK_DUMP(HCLK_PERILP1, "hclk_perilp1", true),
918b75ff34SElaine Zhang 	RK3399_CLK_DUMP(PCLK_PERILP1, "pclk_perilp1", true),
928b75ff34SElaine Zhang };
938b75ff34SElaine Zhang #endif
948b75ff34SElaine Zhang 
95aff8795cSHeiko Stübner enum {
96aff8795cSHeiko Stübner 	/* PLL_CON0 */
97aff8795cSHeiko Stübner 	PLL_FBDIV_MASK			= 0xfff,
98aff8795cSHeiko Stübner 	PLL_FBDIV_SHIFT			= 0,
99aff8795cSHeiko Stübner 
100aff8795cSHeiko Stübner 	/* PLL_CON1 */
101aff8795cSHeiko Stübner 	PLL_POSTDIV2_SHIFT		= 12,
102aff8795cSHeiko Stübner 	PLL_POSTDIV2_MASK		= 0x7 << PLL_POSTDIV2_SHIFT,
103aff8795cSHeiko Stübner 	PLL_POSTDIV1_SHIFT		= 8,
104aff8795cSHeiko Stübner 	PLL_POSTDIV1_MASK		= 0x7 << PLL_POSTDIV1_SHIFT,
105aff8795cSHeiko Stübner 	PLL_REFDIV_MASK			= 0x3f,
106aff8795cSHeiko Stübner 	PLL_REFDIV_SHIFT		= 0,
107aff8795cSHeiko Stübner 
108aff8795cSHeiko Stübner 	/* PLL_CON2 */
109aff8795cSHeiko Stübner 	PLL_LOCK_STATUS_SHIFT		= 31,
110aff8795cSHeiko Stübner 	PLL_LOCK_STATUS_MASK		= 1 << PLL_LOCK_STATUS_SHIFT,
111aff8795cSHeiko Stübner 	PLL_FRACDIV_MASK		= 0xffffff,
112aff8795cSHeiko Stübner 	PLL_FRACDIV_SHIFT		= 0,
113aff8795cSHeiko Stübner 
114aff8795cSHeiko Stübner 	/* PLL_CON3 */
115aff8795cSHeiko Stübner 	PLL_MODE_SHIFT			= 8,
116aff8795cSHeiko Stübner 	PLL_MODE_MASK			= 3 << PLL_MODE_SHIFT,
117aff8795cSHeiko Stübner 	PLL_MODE_SLOW			= 0,
118aff8795cSHeiko Stübner 	PLL_MODE_NORM,
119aff8795cSHeiko Stübner 	PLL_MODE_DEEP,
120aff8795cSHeiko Stübner 	PLL_DSMPD_SHIFT			= 3,
121aff8795cSHeiko Stübner 	PLL_DSMPD_MASK			= 1 << PLL_DSMPD_SHIFT,
122aff8795cSHeiko Stübner 	PLL_INTEGER_MODE		= 1,
123aff8795cSHeiko Stübner 
124aff8795cSHeiko Stübner 	/* PMUCRU_CLKSEL_CON0 */
125aff8795cSHeiko Stübner 	PMU_PCLK_DIV_CON_MASK		= 0x1f,
126aff8795cSHeiko Stübner 	PMU_PCLK_DIV_CON_SHIFT		= 0,
127aff8795cSHeiko Stübner 
128aff8795cSHeiko Stübner 	/* PMUCRU_CLKSEL_CON1 */
129aff8795cSHeiko Stübner 	SPI3_PLL_SEL_SHIFT		= 7,
130aff8795cSHeiko Stübner 	SPI3_PLL_SEL_MASK		= 1 << SPI3_PLL_SEL_SHIFT,
131aff8795cSHeiko Stübner 	SPI3_PLL_SEL_24M		= 0,
132aff8795cSHeiko Stübner 	SPI3_PLL_SEL_PPLL		= 1,
133aff8795cSHeiko Stübner 	SPI3_DIV_CON_SHIFT		= 0x0,
134aff8795cSHeiko Stübner 	SPI3_DIV_CON_MASK		= 0x7f,
135aff8795cSHeiko Stübner 
136aff8795cSHeiko Stübner 	/* PMUCRU_CLKSEL_CON2 */
137aff8795cSHeiko Stübner 	I2C_DIV_CON_MASK		= 0x7f,
1385e79f443SKever Yang 	CLK_I2C8_DIV_CON_SHIFT		= 8,
1395e79f443SKever Yang 	CLK_I2C0_DIV_CON_SHIFT		= 0,
140aff8795cSHeiko Stübner 
141aff8795cSHeiko Stübner 	/* PMUCRU_CLKSEL_CON3 */
1425e79f443SKever Yang 	CLK_I2C4_DIV_CON_SHIFT		= 0,
143aff8795cSHeiko Stübner 
144ccced9e1SLin Huang 	/* CLKSEL_CON0 / CLKSEL_CON2 */
145ccced9e1SLin Huang 	ACLKM_CORE_DIV_CON_MASK	= 0x1f,
146ccced9e1SLin Huang 	ACLKM_CORE_DIV_CON_SHIFT	= 8,
147ccced9e1SLin Huang 	CLK_CORE_PLL_SEL_MASK		= 3,
148ccced9e1SLin Huang 	CLK_CORE_PLL_SEL_SHIFT		= 6,
149ccced9e1SLin Huang 	CLK_CORE_PLL_SEL_ALPLL		= 0x0,
150ccced9e1SLin Huang 	CLK_CORE_PLL_SEL_ABPLL		= 0x1,
151ccced9e1SLin Huang 	CLK_CORE_PLL_SEL_DPLL		= 0x10,
152ccced9e1SLin Huang 	CLK_CORE_PLL_SEL_GPLL		= 0x11,
153ccced9e1SLin Huang 	CLK_CORE_DIV_MASK		= 0x1f,
154ccced9e1SLin Huang 	CLK_CORE_DIV_SHIFT		= 0,
155aff8795cSHeiko Stübner 
156ccced9e1SLin Huang 	/* CLKSEL_CON1 / CLKSEL_CON3 */
157ccced9e1SLin Huang 	PCLK_DBG_DIV_MASK		= 0x1f,
158ccced9e1SLin Huang 	PCLK_DBG_DIV_SHIFT		= 0x8,
159ccced9e1SLin Huang 	ATCLK_CORE_DIV_MASK		= 0x1f,
160ccced9e1SLin Huang 	ATCLK_CORE_DIV_SHIFT		= 0,
161aff8795cSHeiko Stübner 
162aff8795cSHeiko Stübner 	/* CLKSEL_CON14 */
163aff8795cSHeiko Stübner 	PCLK_PERIHP_DIV_CON_SHIFT	= 12,
164aff8795cSHeiko Stübner 	PCLK_PERIHP_DIV_CON_MASK	= 0x7 << PCLK_PERIHP_DIV_CON_SHIFT,
165aff8795cSHeiko Stübner 	HCLK_PERIHP_DIV_CON_SHIFT	= 8,
166aff8795cSHeiko Stübner 	HCLK_PERIHP_DIV_CON_MASK	= 3 << HCLK_PERIHP_DIV_CON_SHIFT,
167aff8795cSHeiko Stübner 	ACLK_PERIHP_PLL_SEL_SHIFT	= 7,
168aff8795cSHeiko Stübner 	ACLK_PERIHP_PLL_SEL_MASK	= 1 << ACLK_PERIHP_PLL_SEL_SHIFT,
169aff8795cSHeiko Stübner 	ACLK_PERIHP_PLL_SEL_CPLL	= 0,
170aff8795cSHeiko Stübner 	ACLK_PERIHP_PLL_SEL_GPLL	= 1,
171aff8795cSHeiko Stübner 	ACLK_PERIHP_DIV_CON_SHIFT	= 0,
172aff8795cSHeiko Stübner 	ACLK_PERIHP_DIV_CON_MASK	= 0x1f,
173aff8795cSHeiko Stübner 
174aff8795cSHeiko Stübner 	/* CLKSEL_CON21 */
175aff8795cSHeiko Stübner 	ACLK_EMMC_PLL_SEL_SHIFT         = 7,
176aff8795cSHeiko Stübner 	ACLK_EMMC_PLL_SEL_MASK          = 0x1 << ACLK_EMMC_PLL_SEL_SHIFT,
177aff8795cSHeiko Stübner 	ACLK_EMMC_PLL_SEL_GPLL          = 0x1,
178aff8795cSHeiko Stübner 	ACLK_EMMC_DIV_CON_SHIFT         = 0,
179aff8795cSHeiko Stübner 	ACLK_EMMC_DIV_CON_MASK          = 0x1f,
180aff8795cSHeiko Stübner 
181aff8795cSHeiko Stübner 	/* CLKSEL_CON22 */
182aff8795cSHeiko Stübner 	CLK_EMMC_PLL_SHIFT              = 8,
183aff8795cSHeiko Stübner 	CLK_EMMC_PLL_MASK               = 0x7 << CLK_EMMC_PLL_SHIFT,
184aff8795cSHeiko Stübner 	CLK_EMMC_PLL_SEL_GPLL           = 0x1,
185fd4b2dc0SKever Yang 	CLK_EMMC_PLL_SEL_24M            = 0x5,
186aff8795cSHeiko Stübner 	CLK_EMMC_DIV_CON_SHIFT          = 0,
187aff8795cSHeiko Stübner 	CLK_EMMC_DIV_CON_MASK           = 0x7f << CLK_EMMC_DIV_CON_SHIFT,
188aff8795cSHeiko Stübner 
189aff8795cSHeiko Stübner 	/* CLKSEL_CON23 */
190aff8795cSHeiko Stübner 	PCLK_PERILP0_DIV_CON_SHIFT	= 12,
191aff8795cSHeiko Stübner 	PCLK_PERILP0_DIV_CON_MASK	= 0x7 << PCLK_PERILP0_DIV_CON_SHIFT,
192aff8795cSHeiko Stübner 	HCLK_PERILP0_DIV_CON_SHIFT	= 8,
193aff8795cSHeiko Stübner 	HCLK_PERILP0_DIV_CON_MASK	= 3 << HCLK_PERILP0_DIV_CON_SHIFT,
194aff8795cSHeiko Stübner 	ACLK_PERILP0_PLL_SEL_SHIFT	= 7,
195aff8795cSHeiko Stübner 	ACLK_PERILP0_PLL_SEL_MASK	= 1 << ACLK_PERILP0_PLL_SEL_SHIFT,
196aff8795cSHeiko Stübner 	ACLK_PERILP0_PLL_SEL_CPLL	= 0,
197aff8795cSHeiko Stübner 	ACLK_PERILP0_PLL_SEL_GPLL	= 1,
198aff8795cSHeiko Stübner 	ACLK_PERILP0_DIV_CON_SHIFT	= 0,
199aff8795cSHeiko Stübner 	ACLK_PERILP0_DIV_CON_MASK	= 0x1f,
200aff8795cSHeiko Stübner 
201187d951bSElaine Zhang 	/* CRU_CLK_SEL24_CON */
202187d951bSElaine Zhang 	CRYPTO0_PLL_SEL_SHIFT		= 6,
203187d951bSElaine Zhang 	CRYPTO0_PLL_SEL_MASK		= 3 << CRYPTO0_PLL_SEL_SHIFT,
204187d951bSElaine Zhang 	CRYPTO_PLL_SEL_CPLL		= 0,
205187d951bSElaine Zhang 	CRYPTO_PLL_SEL_GPLL,
206187d951bSElaine Zhang 	CRYPTO_PLL_SEL_PPLL		= 0,
207187d951bSElaine Zhang 	CRYPTO0_DIV_SHIFT		= 0,
208187d951bSElaine Zhang 	CRYPTO0_DIV_MASK		= 0x1f << CRYPTO0_DIV_SHIFT,
209187d951bSElaine Zhang 
210aff8795cSHeiko Stübner 	/* CLKSEL_CON25 */
211aff8795cSHeiko Stübner 	PCLK_PERILP1_DIV_CON_SHIFT	= 8,
212aff8795cSHeiko Stübner 	PCLK_PERILP1_DIV_CON_MASK	= 0x7 << PCLK_PERILP1_DIV_CON_SHIFT,
213aff8795cSHeiko Stübner 	HCLK_PERILP1_PLL_SEL_SHIFT	= 7,
214aff8795cSHeiko Stübner 	HCLK_PERILP1_PLL_SEL_MASK	= 1 << HCLK_PERILP1_PLL_SEL_SHIFT,
215aff8795cSHeiko Stübner 	HCLK_PERILP1_PLL_SEL_CPLL	= 0,
216aff8795cSHeiko Stübner 	HCLK_PERILP1_PLL_SEL_GPLL	= 1,
217aff8795cSHeiko Stübner 	HCLK_PERILP1_DIV_CON_SHIFT	= 0,
218aff8795cSHeiko Stübner 	HCLK_PERILP1_DIV_CON_MASK	= 0x1f,
219aff8795cSHeiko Stübner 
220aff8795cSHeiko Stübner 	/* CLKSEL_CON26 */
221aff8795cSHeiko Stübner 	CLK_SARADC_DIV_CON_SHIFT	= 8,
222e78991bfSDavid Wu 	CLK_SARADC_DIV_CON_MASK		= GENMASK(15, 8),
223e78991bfSDavid Wu 	CLK_SARADC_DIV_CON_WIDTH	= 8,
224187d951bSElaine Zhang 	CRYPTO1_PLL_SEL_SHIFT		= 6,
225187d951bSElaine Zhang 	CRYPTO1_PLL_SEL_MASK		= 3 << CRYPTO1_PLL_SEL_SHIFT,
226187d951bSElaine Zhang 	CRYPTO1_DIV_SHIFT		= 0,
227187d951bSElaine Zhang 	CRYPTO1_DIV_MASK		= 0x1f << CRYPTO1_DIV_SHIFT,
228aff8795cSHeiko Stübner 
229aff8795cSHeiko Stübner 	/* CLKSEL_CON27 */
230aff8795cSHeiko Stübner 	CLK_TSADC_SEL_X24M		= 0x0,
231aff8795cSHeiko Stübner 	CLK_TSADC_SEL_SHIFT		= 15,
232aff8795cSHeiko Stübner 	CLK_TSADC_SEL_MASK		= 1 << CLK_TSADC_SEL_SHIFT,
233aff8795cSHeiko Stübner 	CLK_TSADC_DIV_CON_SHIFT		= 0,
234aff8795cSHeiko Stübner 	CLK_TSADC_DIV_CON_MASK		= 0x3ff,
235aff8795cSHeiko Stübner 
236aff8795cSHeiko Stübner 	/* CLKSEL_CON47 & CLKSEL_CON48 */
237aff8795cSHeiko Stübner 	ACLK_VOP_PLL_SEL_SHIFT		= 6,
238aff8795cSHeiko Stübner 	ACLK_VOP_PLL_SEL_MASK		= 0x3 << ACLK_VOP_PLL_SEL_SHIFT,
239aff8795cSHeiko Stübner 	ACLK_VOP_PLL_SEL_CPLL		= 0x1,
2406bfdfc4fSElaine Zhang 	ACLK_VOP_PLL_SEL_GPLL		= 0x2,
241aff8795cSHeiko Stübner 	ACLK_VOP_DIV_CON_SHIFT		= 0,
242aff8795cSHeiko Stübner 	ACLK_VOP_DIV_CON_MASK		= 0x1f << ACLK_VOP_DIV_CON_SHIFT,
243aff8795cSHeiko Stübner 
244aff8795cSHeiko Stübner 	/* CLKSEL_CON49 & CLKSEL_CON50 */
245aff8795cSHeiko Stübner 	DCLK_VOP_DCLK_SEL_SHIFT         = 11,
246aff8795cSHeiko Stübner 	DCLK_VOP_DCLK_SEL_MASK          = 1 << DCLK_VOP_DCLK_SEL_SHIFT,
247aff8795cSHeiko Stübner 	DCLK_VOP_DCLK_SEL_DIVOUT        = 0,
248aff8795cSHeiko Stübner 	DCLK_VOP_PLL_SEL_SHIFT          = 8,
249aff8795cSHeiko Stübner 	DCLK_VOP_PLL_SEL_MASK           = 3 << DCLK_VOP_PLL_SEL_SHIFT,
250aff8795cSHeiko Stübner 	DCLK_VOP_PLL_SEL_VPLL           = 0,
2516bfdfc4fSElaine Zhang 	DCLK_VOP_PLL_SEL_CPLL           = 1,
252aff8795cSHeiko Stübner 	DCLK_VOP_DIV_CON_MASK           = 0xff,
253aff8795cSHeiko Stübner 	DCLK_VOP_DIV_CON_SHIFT          = 0,
254aff8795cSHeiko Stübner 
255981ee0bdSElaine Zhang 	/* CLKSEL_CON57 */
256981ee0bdSElaine Zhang 	PCLK_ALIVE_DIV_CON_SHIFT	= 0,
257981ee0bdSElaine Zhang 	PCLK_ALIVE_DIV_CON_MASK		= 0x1f << PCLK_ALIVE_DIV_CON_SHIFT,
258981ee0bdSElaine Zhang 
259aff8795cSHeiko Stübner 	/* CLKSEL_CON58 */
2608fa6979bSPhilipp Tomsich 	CLK_SPI_PLL_SEL_WIDTH = 1,
2618fa6979bSPhilipp Tomsich 	CLK_SPI_PLL_SEL_MASK = ((1 < CLK_SPI_PLL_SEL_WIDTH) - 1),
262aff8795cSHeiko Stübner 	CLK_SPI_PLL_SEL_CPLL = 0,
263aff8795cSHeiko Stübner 	CLK_SPI_PLL_SEL_GPLL = 1,
2648fa6979bSPhilipp Tomsich 	CLK_SPI_PLL_DIV_CON_WIDTH = 7,
2658fa6979bSPhilipp Tomsich 	CLK_SPI_PLL_DIV_CON_MASK = ((1 << CLK_SPI_PLL_DIV_CON_WIDTH) - 1),
2668fa6979bSPhilipp Tomsich 
267aff8795cSHeiko Stübner 	CLK_SPI5_PLL_DIV_CON_SHIFT      = 8,
268aff8795cSHeiko Stübner 	CLK_SPI5_PLL_SEL_SHIFT	        = 15,
269aff8795cSHeiko Stübner 
270aff8795cSHeiko Stübner 	/* CLKSEL_CON59 */
271aff8795cSHeiko Stübner 	CLK_SPI1_PLL_SEL_SHIFT		= 15,
272aff8795cSHeiko Stübner 	CLK_SPI1_PLL_DIV_CON_SHIFT	= 8,
273aff8795cSHeiko Stübner 	CLK_SPI0_PLL_SEL_SHIFT		= 7,
274aff8795cSHeiko Stübner 	CLK_SPI0_PLL_DIV_CON_SHIFT	= 0,
275aff8795cSHeiko Stübner 
276aff8795cSHeiko Stübner 	/* CLKSEL_CON60 */
277aff8795cSHeiko Stübner 	CLK_SPI4_PLL_SEL_SHIFT		= 15,
278aff8795cSHeiko Stübner 	CLK_SPI4_PLL_DIV_CON_SHIFT	= 8,
279aff8795cSHeiko Stübner 	CLK_SPI2_PLL_SEL_SHIFT		= 7,
280aff8795cSHeiko Stübner 	CLK_SPI2_PLL_DIV_CON_SHIFT	= 0,
281aff8795cSHeiko Stübner 
282aff8795cSHeiko Stübner 	/* CLKSEL_CON61 */
283aff8795cSHeiko Stübner 	CLK_I2C_PLL_SEL_MASK		= 1,
284aff8795cSHeiko Stübner 	CLK_I2C_PLL_SEL_CPLL		= 0,
285aff8795cSHeiko Stübner 	CLK_I2C_PLL_SEL_GPLL		= 1,
286aff8795cSHeiko Stübner 	CLK_I2C5_PLL_SEL_SHIFT		= 15,
287aff8795cSHeiko Stübner 	CLK_I2C5_DIV_CON_SHIFT		= 8,
288aff8795cSHeiko Stübner 	CLK_I2C1_PLL_SEL_SHIFT		= 7,
289aff8795cSHeiko Stübner 	CLK_I2C1_DIV_CON_SHIFT		= 0,
290aff8795cSHeiko Stübner 
291aff8795cSHeiko Stübner 	/* CLKSEL_CON62 */
292aff8795cSHeiko Stübner 	CLK_I2C6_PLL_SEL_SHIFT		= 15,
293aff8795cSHeiko Stübner 	CLK_I2C6_DIV_CON_SHIFT		= 8,
294aff8795cSHeiko Stübner 	CLK_I2C2_PLL_SEL_SHIFT		= 7,
295aff8795cSHeiko Stübner 	CLK_I2C2_DIV_CON_SHIFT		= 0,
296aff8795cSHeiko Stübner 
297aff8795cSHeiko Stübner 	/* CLKSEL_CON63 */
298aff8795cSHeiko Stübner 	CLK_I2C7_PLL_SEL_SHIFT		= 15,
299aff8795cSHeiko Stübner 	CLK_I2C7_DIV_CON_SHIFT		= 8,
300aff8795cSHeiko Stübner 	CLK_I2C3_PLL_SEL_SHIFT		= 7,
301aff8795cSHeiko Stübner 	CLK_I2C3_DIV_CON_SHIFT		= 0,
302aff8795cSHeiko Stübner 
303aff8795cSHeiko Stübner 	/* CRU_SOFTRST_CON4 */
304aff8795cSHeiko Stübner 	RESETN_DDR0_REQ_SHIFT		= 8,
305aff8795cSHeiko Stübner 	RESETN_DDR0_REQ_MASK		= 1 << RESETN_DDR0_REQ_SHIFT,
306aff8795cSHeiko Stübner 	RESETN_DDRPHY0_REQ_SHIFT	= 9,
307aff8795cSHeiko Stübner 	RESETN_DDRPHY0_REQ_MASK		= 1 << RESETN_DDRPHY0_REQ_SHIFT,
308aff8795cSHeiko Stübner 	RESETN_DDR1_REQ_SHIFT		= 12,
309aff8795cSHeiko Stübner 	RESETN_DDR1_REQ_MASK		= 1 << RESETN_DDR1_REQ_SHIFT,
310aff8795cSHeiko Stübner 	RESETN_DDRPHY1_REQ_SHIFT	= 13,
311aff8795cSHeiko Stübner 	RESETN_DDRPHY1_REQ_MASK		= 1 << RESETN_DDRPHY1_REQ_SHIFT,
312aff8795cSHeiko Stübner };
313aff8795cSHeiko Stübner 
314aff8795cSHeiko Stübner #define VCO_MAX_KHZ	(3200 * (MHz / KHz))
315aff8795cSHeiko Stübner #define VCO_MIN_KHZ	(800 * (MHz / KHz))
316aff8795cSHeiko Stübner #define OUTPUT_MAX_KHZ	(3200 * (MHz / KHz))
317aff8795cSHeiko Stübner #define OUTPUT_MIN_KHZ	(16 * (MHz / KHz))
318aff8795cSHeiko Stübner 
319aff8795cSHeiko Stübner /*
320aff8795cSHeiko Stübner  *  the div restructions of pll in integer mode, these are defined in
321aff8795cSHeiko Stübner  *  * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0
322aff8795cSHeiko Stübner  */
323aff8795cSHeiko Stübner #define PLL_DIV_MIN	16
324aff8795cSHeiko Stübner #define PLL_DIV_MAX	3200
325aff8795cSHeiko Stübner 
326aff8795cSHeiko Stübner /*
327aff8795cSHeiko Stübner  * How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
328aff8795cSHeiko Stübner  * Formulas also embedded within the Fractional PLL Verilog model:
329aff8795cSHeiko Stübner  * If DSMPD = 1 (DSM is disabled, "integer mode")
330aff8795cSHeiko Stübner  * FOUTVCO = FREF / REFDIV * FBDIV
331aff8795cSHeiko Stübner  * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
332aff8795cSHeiko Stübner  * Where:
333aff8795cSHeiko Stübner  * FOUTVCO = Fractional PLL non-divided output frequency
334aff8795cSHeiko Stübner  * FOUTPOSTDIV = Fractional PLL divided output frequency
335aff8795cSHeiko Stübner  *               (output of second post divider)
336aff8795cSHeiko Stübner  * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
337aff8795cSHeiko Stübner  * REFDIV = Fractional PLL input reference clock divider
338aff8795cSHeiko Stübner  * FBDIV = Integer value programmed into feedback divide
339aff8795cSHeiko Stübner  *
340aff8795cSHeiko Stübner  */
3416bfdfc4fSElaine Zhang 
rkclk_pll_get_rate(u32 * pll_con)3426bfdfc4fSElaine Zhang static uint32_t rkclk_pll_get_rate(u32 *pll_con)
3436bfdfc4fSElaine Zhang {
3446bfdfc4fSElaine Zhang 	u32 refdiv, fbdiv, postdiv1, postdiv2;
3456bfdfc4fSElaine Zhang 	u32 con;
3466bfdfc4fSElaine Zhang 
3476bfdfc4fSElaine Zhang 	con = readl(&pll_con[3]);
3486bfdfc4fSElaine Zhang 	switch ((con & PLL_MODE_MASK) >> PLL_MODE_SHIFT) {
3496bfdfc4fSElaine Zhang 	case PLL_MODE_SLOW:
3506bfdfc4fSElaine Zhang 		return OSC_HZ;
3516bfdfc4fSElaine Zhang 	case PLL_MODE_NORM:
3526bfdfc4fSElaine Zhang 		/* normal mode */
3536bfdfc4fSElaine Zhang 		con = readl(&pll_con[0]);
3546bfdfc4fSElaine Zhang 		fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
3556bfdfc4fSElaine Zhang 		con = readl(&pll_con[1]);
3566bfdfc4fSElaine Zhang 		postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
3576bfdfc4fSElaine Zhang 		postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
3586bfdfc4fSElaine Zhang 		refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
3596bfdfc4fSElaine Zhang 		return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
3606bfdfc4fSElaine Zhang 	case PLL_MODE_DEEP:
3616bfdfc4fSElaine Zhang 	default:
3626bfdfc4fSElaine Zhang 		return 32768;
3636bfdfc4fSElaine Zhang 	}
3646bfdfc4fSElaine Zhang }
3656bfdfc4fSElaine Zhang 
rkclk_set_pll(u32 * pll_con,const struct pll_div * div)366aff8795cSHeiko Stübner static void rkclk_set_pll(u32 *pll_con, const struct pll_div *div)
367aff8795cSHeiko Stübner {
368aff8795cSHeiko Stübner 	/* All 8 PLLs have same VCO and output frequency range restrictions. */
369aff8795cSHeiko Stübner 	u32 vco_khz = OSC_HZ / 1000 * div->fbdiv / div->refdiv;
370aff8795cSHeiko Stübner 	u32 output_khz = vco_khz / div->postdiv1 / div->postdiv2;
371aff8795cSHeiko Stübner 
372aff8795cSHeiko Stübner 	debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, "
373aff8795cSHeiko Stübner 			   "postdiv2=%d, vco=%u khz, output=%u khz\n",
374aff8795cSHeiko Stübner 			   pll_con, div->fbdiv, div->refdiv, div->postdiv1,
375aff8795cSHeiko Stübner 			   div->postdiv2, vco_khz, output_khz);
376aff8795cSHeiko Stübner 	assert(vco_khz >= VCO_MIN_KHZ && vco_khz <= VCO_MAX_KHZ &&
377aff8795cSHeiko Stübner 	       output_khz >= OUTPUT_MIN_KHZ && output_khz <= OUTPUT_MAX_KHZ &&
378aff8795cSHeiko Stübner 	       div->fbdiv >= PLL_DIV_MIN && div->fbdiv <= PLL_DIV_MAX);
379aff8795cSHeiko Stübner 
380aff8795cSHeiko Stübner 	/*
381aff8795cSHeiko Stübner 	 * When power on or changing PLL setting,
382aff8795cSHeiko Stübner 	 * we must force PLL into slow mode to ensure output stable clock.
383aff8795cSHeiko Stübner 	 */
384aff8795cSHeiko Stübner 	rk_clrsetreg(&pll_con[3], PLL_MODE_MASK,
385aff8795cSHeiko Stübner 		     PLL_MODE_SLOW << PLL_MODE_SHIFT);
386aff8795cSHeiko Stübner 
387aff8795cSHeiko Stübner 	/* use integer mode */
388aff8795cSHeiko Stübner 	rk_clrsetreg(&pll_con[3], PLL_DSMPD_MASK,
389aff8795cSHeiko Stübner 		     PLL_INTEGER_MODE << PLL_DSMPD_SHIFT);
390aff8795cSHeiko Stübner 
391aff8795cSHeiko Stübner 	rk_clrsetreg(&pll_con[0], PLL_FBDIV_MASK,
392aff8795cSHeiko Stübner 		     div->fbdiv << PLL_FBDIV_SHIFT);
393aff8795cSHeiko Stübner 	rk_clrsetreg(&pll_con[1],
394aff8795cSHeiko Stübner 		     PLL_POSTDIV2_MASK | PLL_POSTDIV1_MASK |
395aff8795cSHeiko Stübner 		     PLL_REFDIV_MASK | PLL_REFDIV_SHIFT,
396aff8795cSHeiko Stübner 		     (div->postdiv2 << PLL_POSTDIV2_SHIFT) |
397aff8795cSHeiko Stübner 		     (div->postdiv1 << PLL_POSTDIV1_SHIFT) |
398aff8795cSHeiko Stübner 		     (div->refdiv << PLL_REFDIV_SHIFT));
399aff8795cSHeiko Stübner 
400aff8795cSHeiko Stübner 	/* waiting for pll lock */
401aff8795cSHeiko Stübner 	while (!(readl(&pll_con[2]) & (1 << PLL_LOCK_STATUS_SHIFT)))
402aff8795cSHeiko Stübner 		udelay(1);
403aff8795cSHeiko Stübner 
404aff8795cSHeiko Stübner 	/* pll enter normal mode */
405aff8795cSHeiko Stübner 	rk_clrsetreg(&pll_con[3], PLL_MODE_MASK,
406aff8795cSHeiko Stübner 		     PLL_MODE_NORM << PLL_MODE_SHIFT);
407aff8795cSHeiko Stübner }
408aff8795cSHeiko Stübner 
rk3399_pll_get_rate(struct rk3399_clk_priv * priv,enum rk3399_pll_id pll_id)4096bfdfc4fSElaine Zhang static ulong rk3399_pll_get_rate(struct rk3399_clk_priv *priv,
4106bfdfc4fSElaine Zhang 				 enum rk3399_pll_id pll_id)
4116bfdfc4fSElaine Zhang {
4126bfdfc4fSElaine Zhang 	struct rk3399_cru *cru = priv->cru;
4136bfdfc4fSElaine Zhang 	u32 *pll_con;
4146bfdfc4fSElaine Zhang 
4156bfdfc4fSElaine Zhang 	switch (pll_id) {
4166bfdfc4fSElaine Zhang 	case PLL_APLLL:
4176bfdfc4fSElaine Zhang 		pll_con = &cru->apll_l_con[0];
4186bfdfc4fSElaine Zhang 		break;
4196bfdfc4fSElaine Zhang 	case PLL_APLLB:
4206bfdfc4fSElaine Zhang 		pll_con = &cru->apll_b_con[0];
4216bfdfc4fSElaine Zhang 		break;
4226bfdfc4fSElaine Zhang 	case PLL_DPLL:
4236bfdfc4fSElaine Zhang 		pll_con = &cru->dpll_con[0];
4246bfdfc4fSElaine Zhang 		break;
4256bfdfc4fSElaine Zhang 	case PLL_CPLL:
4266bfdfc4fSElaine Zhang 		pll_con = &cru->cpll_con[0];
4276bfdfc4fSElaine Zhang 		break;
4286bfdfc4fSElaine Zhang 	case PLL_GPLL:
4296bfdfc4fSElaine Zhang 		pll_con = &cru->gpll_con[0];
4306bfdfc4fSElaine Zhang 		break;
4316bfdfc4fSElaine Zhang 	case PLL_NPLL:
4326bfdfc4fSElaine Zhang 		pll_con = &cru->npll_con[0];
4336bfdfc4fSElaine Zhang 		break;
4346bfdfc4fSElaine Zhang 	case PLL_VPLL:
4356bfdfc4fSElaine Zhang 		pll_con = &cru->vpll_con[0];
4366bfdfc4fSElaine Zhang 		break;
4376bfdfc4fSElaine Zhang 	default:
4386bfdfc4fSElaine Zhang 		pll_con = &cru->vpll_con[0];
4396bfdfc4fSElaine Zhang 		break;
4406bfdfc4fSElaine Zhang 	}
4416bfdfc4fSElaine Zhang 
4426bfdfc4fSElaine Zhang 	return rkclk_pll_get_rate(pll_con);
4436bfdfc4fSElaine Zhang }
4446bfdfc4fSElaine Zhang 
pll_para_config(u32 freq_hz,struct pll_div * div)445aff8795cSHeiko Stübner static int pll_para_config(u32 freq_hz, struct pll_div *div)
446aff8795cSHeiko Stübner {
447aff8795cSHeiko Stübner 	u32 ref_khz = OSC_HZ / KHz, refdiv, fbdiv = 0;
448aff8795cSHeiko Stübner 	u32 postdiv1, postdiv2 = 1;
449aff8795cSHeiko Stübner 	u32 fref_khz;
450aff8795cSHeiko Stübner 	u32 diff_khz, best_diff_khz;
451aff8795cSHeiko Stübner 	const u32 max_refdiv = 63, max_fbdiv = 3200, min_fbdiv = 16;
452aff8795cSHeiko Stübner 	const u32 max_postdiv1 = 7, max_postdiv2 = 7;
453aff8795cSHeiko Stübner 	u32 vco_khz;
454aff8795cSHeiko Stübner 	u32 freq_khz = freq_hz / KHz;
455aff8795cSHeiko Stübner 
456aff8795cSHeiko Stübner 	if (!freq_hz) {
457aff8795cSHeiko Stübner 		printf("%s: the frequency can't be 0 Hz\n", __func__);
458aff8795cSHeiko Stübner 		return -1;
459aff8795cSHeiko Stübner 	}
460aff8795cSHeiko Stübner 
461aff8795cSHeiko Stübner 	postdiv1 = DIV_ROUND_UP(VCO_MIN_KHZ, freq_khz);
462aff8795cSHeiko Stübner 	if (postdiv1 > max_postdiv1) {
463aff8795cSHeiko Stübner 		postdiv2 = DIV_ROUND_UP(postdiv1, max_postdiv1);
464aff8795cSHeiko Stübner 		postdiv1 = DIV_ROUND_UP(postdiv1, postdiv2);
465aff8795cSHeiko Stübner 	}
466aff8795cSHeiko Stübner 
467aff8795cSHeiko Stübner 	vco_khz = freq_khz * postdiv1 * postdiv2;
468aff8795cSHeiko Stübner 
469aff8795cSHeiko Stübner 	if (vco_khz < VCO_MIN_KHZ || vco_khz > VCO_MAX_KHZ ||
470aff8795cSHeiko Stübner 	    postdiv2 > max_postdiv2) {
471aff8795cSHeiko Stübner 		printf("%s: Cannot find out a supported VCO"
472aff8795cSHeiko Stübner 		       " for Frequency (%uHz).\n", __func__, freq_hz);
473aff8795cSHeiko Stübner 		return -1;
474aff8795cSHeiko Stübner 	}
475aff8795cSHeiko Stübner 
476aff8795cSHeiko Stübner 	div->postdiv1 = postdiv1;
477aff8795cSHeiko Stübner 	div->postdiv2 = postdiv2;
478aff8795cSHeiko Stübner 
479aff8795cSHeiko Stübner 	best_diff_khz = vco_khz;
480aff8795cSHeiko Stübner 	for (refdiv = 1; refdiv < max_refdiv && best_diff_khz; refdiv++) {
481aff8795cSHeiko Stübner 		fref_khz = ref_khz / refdiv;
482aff8795cSHeiko Stübner 
483aff8795cSHeiko Stübner 		fbdiv = vco_khz / fref_khz;
484aff8795cSHeiko Stübner 		if ((fbdiv >= max_fbdiv) || (fbdiv <= min_fbdiv))
485aff8795cSHeiko Stübner 			continue;
486aff8795cSHeiko Stübner 		diff_khz = vco_khz - fbdiv * fref_khz;
487aff8795cSHeiko Stübner 		if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) {
488aff8795cSHeiko Stübner 			fbdiv++;
489aff8795cSHeiko Stübner 			diff_khz = fref_khz - diff_khz;
490aff8795cSHeiko Stübner 		}
491aff8795cSHeiko Stübner 
492aff8795cSHeiko Stübner 		if (diff_khz >= best_diff_khz)
493aff8795cSHeiko Stübner 			continue;
494aff8795cSHeiko Stübner 
495aff8795cSHeiko Stübner 		best_diff_khz = diff_khz;
496aff8795cSHeiko Stübner 		div->refdiv = refdiv;
497aff8795cSHeiko Stübner 		div->fbdiv = fbdiv;
498aff8795cSHeiko Stübner 	}
499aff8795cSHeiko Stübner 
500aff8795cSHeiko Stübner 	if (best_diff_khz > 4 * (MHz/KHz)) {
501aff8795cSHeiko Stübner 		printf("%s: Failed to match output frequency %u, "
502aff8795cSHeiko Stübner 		       "difference is %u Hz,exceed 4MHZ\n", __func__, freq_hz,
503aff8795cSHeiko Stübner 		       best_diff_khz * KHz);
504aff8795cSHeiko Stübner 		return -1;
505aff8795cSHeiko Stübner 	}
506aff8795cSHeiko Stübner 	return 0;
507aff8795cSHeiko Stübner }
508aff8795cSHeiko Stübner 
rk3399_configure_cpu(struct rk3399_cru * cru,enum apll_frequencies freq,enum cpu_cluster cluster)509aff8795cSHeiko Stübner void rk3399_configure_cpu(struct rk3399_cru *cru,
510ccced9e1SLin Huang 			  enum apll_frequencies freq,
511ccced9e1SLin Huang 			  enum cpu_cluster cluster)
512aff8795cSHeiko Stübner {
513aff8795cSHeiko Stübner 	u32 aclkm_div;
514aff8795cSHeiko Stübner 	u32 pclk_dbg_div;
515ccced9e1SLin Huang 	u32 atclk_div, apll_hz;
516ccced9e1SLin Huang 	int con_base, parent;
517ccced9e1SLin Huang 	u32 *pll_con;
518aff8795cSHeiko Stübner 
519ccced9e1SLin Huang 	switch (cluster) {
520ccced9e1SLin Huang 	case CPU_CLUSTER_LITTLE:
521ccced9e1SLin Huang 		con_base = 0;
522ccced9e1SLin Huang 		parent = CLK_CORE_PLL_SEL_ALPLL;
523ccced9e1SLin Huang 		pll_con = &cru->apll_l_con[0];
524ccced9e1SLin Huang 		break;
525ccced9e1SLin Huang 	case CPU_CLUSTER_BIG:
526ccced9e1SLin Huang 	default:
527ccced9e1SLin Huang 		con_base = 2;
528ccced9e1SLin Huang 		parent = CLK_CORE_PLL_SEL_ABPLL;
529ccced9e1SLin Huang 		pll_con = &cru->apll_b_con[0];
530ccced9e1SLin Huang 		break;
531ccced9e1SLin Huang 	}
532aff8795cSHeiko Stübner 
533ccced9e1SLin Huang 	apll_hz = apll_cfgs[freq]->freq;
534ccced9e1SLin Huang 	rkclk_set_pll(pll_con, apll_cfgs[freq]);
535ccced9e1SLin Huang 
536ccced9e1SLin Huang 	aclkm_div = apll_hz / ACLKM_CORE_HZ - 1;
53788c36f12SElaine Zhang 	assert((aclkm_div + 1) * ACLKM_CORE_HZ <= apll_hz &&
538aff8795cSHeiko Stübner 	       aclkm_div < 0x1f);
539aff8795cSHeiko Stübner 
540ccced9e1SLin Huang 	pclk_dbg_div = apll_hz / PCLK_DBG_HZ - 1;
54188c36f12SElaine Zhang 	assert((pclk_dbg_div + 1) * PCLK_DBG_HZ <= apll_hz &&
542aff8795cSHeiko Stübner 	       pclk_dbg_div < 0x1f);
543aff8795cSHeiko Stübner 
544ccced9e1SLin Huang 	atclk_div = apll_hz / ATCLK_CORE_HZ - 1;
54588c36f12SElaine Zhang 	assert((atclk_div + 1) * ATCLK_CORE_HZ <= apll_hz &&
546aff8795cSHeiko Stübner 	       atclk_div < 0x1f);
547aff8795cSHeiko Stübner 
548ccced9e1SLin Huang 	rk_clrsetreg(&cru->clksel_con[con_base],
549ccced9e1SLin Huang 		     ACLKM_CORE_DIV_CON_MASK | CLK_CORE_PLL_SEL_MASK |
550ccced9e1SLin Huang 		     CLK_CORE_DIV_MASK,
551ccced9e1SLin Huang 		     aclkm_div << ACLKM_CORE_DIV_CON_SHIFT |
552ccced9e1SLin Huang 		     parent << CLK_CORE_PLL_SEL_SHIFT |
553ccced9e1SLin Huang 		     0 << CLK_CORE_DIV_SHIFT);
554aff8795cSHeiko Stübner 
555ccced9e1SLin Huang 	rk_clrsetreg(&cru->clksel_con[con_base + 1],
556ccced9e1SLin Huang 		     PCLK_DBG_DIV_MASK | ATCLK_CORE_DIV_MASK,
557ccced9e1SLin Huang 		     pclk_dbg_div << PCLK_DBG_DIV_SHIFT |
558ccced9e1SLin Huang 		     atclk_div << ATCLK_CORE_DIV_SHIFT);
559aff8795cSHeiko Stübner }
560aff8795cSHeiko Stübner #define I2C_CLK_REG_MASK(bus) \
561aff8795cSHeiko Stübner 			(I2C_DIV_CON_MASK << \
562aff8795cSHeiko Stübner 			CLK_I2C ##bus## _DIV_CON_SHIFT | \
563aff8795cSHeiko Stübner 			CLK_I2C_PLL_SEL_MASK << \
564aff8795cSHeiko Stübner 			CLK_I2C ##bus## _PLL_SEL_SHIFT)
565aff8795cSHeiko Stübner 
566aff8795cSHeiko Stübner #define I2C_CLK_REG_VALUE(bus, clk_div) \
567aff8795cSHeiko Stübner 			      ((clk_div - 1) << \
568aff8795cSHeiko Stübner 					CLK_I2C ##bus## _DIV_CON_SHIFT | \
569aff8795cSHeiko Stübner 			      CLK_I2C_PLL_SEL_GPLL << \
570aff8795cSHeiko Stübner 					CLK_I2C ##bus## _PLL_SEL_SHIFT)
571aff8795cSHeiko Stübner 
572aff8795cSHeiko Stübner #define I2C_CLK_DIV_VALUE(con, bus) \
573aff8795cSHeiko Stübner 			(con >> CLK_I2C ##bus## _DIV_CON_SHIFT) & \
574aff8795cSHeiko Stübner 				I2C_DIV_CON_MASK;
575aff8795cSHeiko Stübner 
5765e79f443SKever Yang #define I2C_PMUCLK_REG_MASK(bus) \
5775e79f443SKever Yang 			(I2C_DIV_CON_MASK << \
5785e79f443SKever Yang 			 CLK_I2C ##bus## _DIV_CON_SHIFT)
5795e79f443SKever Yang 
5805e79f443SKever Yang #define I2C_PMUCLK_REG_VALUE(bus, clk_div) \
5815e79f443SKever Yang 				((clk_div - 1) << \
5825e79f443SKever Yang 				CLK_I2C ##bus## _DIV_CON_SHIFT)
5835e79f443SKever Yang 
rk3399_i2c_get_clk(struct rk3399_cru * cru,ulong clk_id)584aff8795cSHeiko Stübner static ulong rk3399_i2c_get_clk(struct rk3399_cru *cru, ulong clk_id)
585aff8795cSHeiko Stübner {
586aff8795cSHeiko Stübner 	u32 div, con;
587aff8795cSHeiko Stübner 
588aff8795cSHeiko Stübner 	switch (clk_id) {
589aff8795cSHeiko Stübner 	case SCLK_I2C1:
590aff8795cSHeiko Stübner 		con = readl(&cru->clksel_con[61]);
591aff8795cSHeiko Stübner 		div = I2C_CLK_DIV_VALUE(con, 1);
592aff8795cSHeiko Stübner 		break;
593aff8795cSHeiko Stübner 	case SCLK_I2C2:
594aff8795cSHeiko Stübner 		con = readl(&cru->clksel_con[62]);
595aff8795cSHeiko Stübner 		div = I2C_CLK_DIV_VALUE(con, 2);
596aff8795cSHeiko Stübner 		break;
597aff8795cSHeiko Stübner 	case SCLK_I2C3:
598aff8795cSHeiko Stübner 		con = readl(&cru->clksel_con[63]);
599aff8795cSHeiko Stübner 		div = I2C_CLK_DIV_VALUE(con, 3);
600aff8795cSHeiko Stübner 		break;
601aff8795cSHeiko Stübner 	case SCLK_I2C5:
602aff8795cSHeiko Stübner 		con = readl(&cru->clksel_con[61]);
603aff8795cSHeiko Stübner 		div = I2C_CLK_DIV_VALUE(con, 5);
604aff8795cSHeiko Stübner 		break;
605aff8795cSHeiko Stübner 	case SCLK_I2C6:
606aff8795cSHeiko Stübner 		con = readl(&cru->clksel_con[62]);
607aff8795cSHeiko Stübner 		div = I2C_CLK_DIV_VALUE(con, 6);
608aff8795cSHeiko Stübner 		break;
609aff8795cSHeiko Stübner 	case SCLK_I2C7:
610aff8795cSHeiko Stübner 		con = readl(&cru->clksel_con[63]);
611aff8795cSHeiko Stübner 		div = I2C_CLK_DIV_VALUE(con, 7);
612aff8795cSHeiko Stübner 		break;
613aff8795cSHeiko Stübner 	default:
614aff8795cSHeiko Stübner 		printf("do not support this i2c bus\n");
615aff8795cSHeiko Stübner 		return -EINVAL;
616aff8795cSHeiko Stübner 	}
617aff8795cSHeiko Stübner 
618aff8795cSHeiko Stübner 	return DIV_TO_RATE(GPLL_HZ, div);
619aff8795cSHeiko Stübner }
620aff8795cSHeiko Stübner 
rk3399_i2c_set_clk(struct rk3399_cru * cru,ulong clk_id,uint hz)621aff8795cSHeiko Stübner static ulong rk3399_i2c_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
622aff8795cSHeiko Stübner {
623aff8795cSHeiko Stübner 	int src_clk_div;
624aff8795cSHeiko Stübner 
625aff8795cSHeiko Stübner 	/* i2c0,4,8 src clock from ppll, i2c1,2,3,5,6,7 src clock from gpll*/
626aff8795cSHeiko Stübner 	src_clk_div = GPLL_HZ / hz;
6275f42424bSLin Huang 	assert(src_clk_div - 1 <= 127);
628aff8795cSHeiko Stübner 
629aff8795cSHeiko Stübner 	switch (clk_id) {
630aff8795cSHeiko Stübner 	case SCLK_I2C1:
631aff8795cSHeiko Stübner 		rk_clrsetreg(&cru->clksel_con[61], I2C_CLK_REG_MASK(1),
632aff8795cSHeiko Stübner 			     I2C_CLK_REG_VALUE(1, src_clk_div));
633aff8795cSHeiko Stübner 		break;
634aff8795cSHeiko Stübner 	case SCLK_I2C2:
635aff8795cSHeiko Stübner 		rk_clrsetreg(&cru->clksel_con[62], I2C_CLK_REG_MASK(2),
636aff8795cSHeiko Stübner 			     I2C_CLK_REG_VALUE(2, src_clk_div));
637aff8795cSHeiko Stübner 		break;
638aff8795cSHeiko Stübner 	case SCLK_I2C3:
639aff8795cSHeiko Stübner 		rk_clrsetreg(&cru->clksel_con[63], I2C_CLK_REG_MASK(3),
640aff8795cSHeiko Stübner 			     I2C_CLK_REG_VALUE(3, src_clk_div));
641aff8795cSHeiko Stübner 		break;
642aff8795cSHeiko Stübner 	case SCLK_I2C5:
643aff8795cSHeiko Stübner 		rk_clrsetreg(&cru->clksel_con[61], I2C_CLK_REG_MASK(5),
644aff8795cSHeiko Stübner 			     I2C_CLK_REG_VALUE(5, src_clk_div));
645aff8795cSHeiko Stübner 		break;
646aff8795cSHeiko Stübner 	case SCLK_I2C6:
647aff8795cSHeiko Stübner 		rk_clrsetreg(&cru->clksel_con[62], I2C_CLK_REG_MASK(6),
648aff8795cSHeiko Stübner 			     I2C_CLK_REG_VALUE(6, src_clk_div));
649aff8795cSHeiko Stübner 		break;
650aff8795cSHeiko Stübner 	case SCLK_I2C7:
651aff8795cSHeiko Stübner 		rk_clrsetreg(&cru->clksel_con[63], I2C_CLK_REG_MASK(7),
652aff8795cSHeiko Stübner 			     I2C_CLK_REG_VALUE(7, src_clk_div));
653aff8795cSHeiko Stübner 		break;
654aff8795cSHeiko Stübner 	default:
655aff8795cSHeiko Stübner 		printf("do not support this i2c bus\n");
656aff8795cSHeiko Stübner 		return -EINVAL;
657aff8795cSHeiko Stübner 	}
658aff8795cSHeiko Stübner 
659beb90a53SPhilipp Tomsich 	return rk3399_i2c_get_clk(cru, clk_id);
660aff8795cSHeiko Stübner }
661aff8795cSHeiko Stübner 
6628fa6979bSPhilipp Tomsich /*
6638fa6979bSPhilipp Tomsich  * RK3399 SPI clocks have a common divider-width (7 bits) and a single bit
6648fa6979bSPhilipp Tomsich  * to select either CPLL or GPLL as the clock-parent. The location within
6658fa6979bSPhilipp Tomsich  * the enclosing CLKSEL_CON (i.e. div_shift and sel_shift) are variable.
6668fa6979bSPhilipp Tomsich  */
6678fa6979bSPhilipp Tomsich 
6688fa6979bSPhilipp Tomsich struct spi_clkreg {
6698fa6979bSPhilipp Tomsich 	uint8_t reg;  /* CLKSEL_CON[reg] register in CRU */
6708fa6979bSPhilipp Tomsich 	uint8_t div_shift;
6718fa6979bSPhilipp Tomsich 	uint8_t sel_shift;
6728fa6979bSPhilipp Tomsich };
6738fa6979bSPhilipp Tomsich 
6748fa6979bSPhilipp Tomsich /*
6758fa6979bSPhilipp Tomsich  * The entries are numbered relative to their offset from SCLK_SPI0.
6768fa6979bSPhilipp Tomsich  *
6778fa6979bSPhilipp Tomsich  * Note that SCLK_SPI3 (which is configured via PMUCRU and requires different
6788fa6979bSPhilipp Tomsich  * logic is not supported).
6798fa6979bSPhilipp Tomsich  */
6808fa6979bSPhilipp Tomsich static const struct spi_clkreg spi_clkregs[] = {
6818fa6979bSPhilipp Tomsich 	[0] = { .reg = 59,
6828fa6979bSPhilipp Tomsich 		.div_shift = CLK_SPI0_PLL_DIV_CON_SHIFT,
6838fa6979bSPhilipp Tomsich 		.sel_shift = CLK_SPI0_PLL_SEL_SHIFT, },
6848fa6979bSPhilipp Tomsich 	[1] = { .reg = 59,
6858fa6979bSPhilipp Tomsich 		.div_shift = CLK_SPI1_PLL_DIV_CON_SHIFT,
6868fa6979bSPhilipp Tomsich 		.sel_shift = CLK_SPI1_PLL_SEL_SHIFT, },
6878fa6979bSPhilipp Tomsich 	[2] = { .reg = 60,
6888fa6979bSPhilipp Tomsich 		.div_shift = CLK_SPI2_PLL_DIV_CON_SHIFT,
6898fa6979bSPhilipp Tomsich 		.sel_shift = CLK_SPI2_PLL_SEL_SHIFT, },
6908fa6979bSPhilipp Tomsich 	[3] = { .reg = 60,
6918fa6979bSPhilipp Tomsich 		.div_shift = CLK_SPI4_PLL_DIV_CON_SHIFT,
6928fa6979bSPhilipp Tomsich 		.sel_shift = CLK_SPI4_PLL_SEL_SHIFT, },
6938fa6979bSPhilipp Tomsich 	[4] = { .reg = 58,
6948fa6979bSPhilipp Tomsich 		.div_shift = CLK_SPI5_PLL_DIV_CON_SHIFT,
6958fa6979bSPhilipp Tomsich 		.sel_shift = CLK_SPI5_PLL_SEL_SHIFT, },
6968fa6979bSPhilipp Tomsich };
6978fa6979bSPhilipp Tomsich 
rk3399_spi_get_clk(struct rk3399_cru * cru,ulong clk_id)6988fa6979bSPhilipp Tomsich static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id)
6998fa6979bSPhilipp Tomsich {
7008fa6979bSPhilipp Tomsich 	const struct spi_clkreg *spiclk = NULL;
7018fa6979bSPhilipp Tomsich 	u32 div, val;
7028fa6979bSPhilipp Tomsich 
7038fa6979bSPhilipp Tomsich 	switch (clk_id) {
7048fa6979bSPhilipp Tomsich 	case SCLK_SPI0 ... SCLK_SPI5:
7058fa6979bSPhilipp Tomsich 		spiclk = &spi_clkregs[clk_id - SCLK_SPI0];
7068fa6979bSPhilipp Tomsich 		break;
7078fa6979bSPhilipp Tomsich 
7088fa6979bSPhilipp Tomsich 	default:
70990aa625cSMasahiro Yamada 		pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id);
7108fa6979bSPhilipp Tomsich 		return -EINVAL;
7118fa6979bSPhilipp Tomsich 	}
7128fa6979bSPhilipp Tomsich 
7138fa6979bSPhilipp Tomsich 	val = readl(&cru->clksel_con[spiclk->reg]);
714feab7f33SPhilipp Tomsich 	div = bitfield_extract(val, spiclk->div_shift,
715feab7f33SPhilipp Tomsich 			       CLK_SPI_PLL_DIV_CON_WIDTH);
7168fa6979bSPhilipp Tomsich 
7178fa6979bSPhilipp Tomsich 	return DIV_TO_RATE(GPLL_HZ, div);
7188fa6979bSPhilipp Tomsich }
7198fa6979bSPhilipp Tomsich 
rk3399_spi_set_clk(struct rk3399_cru * cru,ulong clk_id,uint hz)7208fa6979bSPhilipp Tomsich static ulong rk3399_spi_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
7218fa6979bSPhilipp Tomsich {
7228fa6979bSPhilipp Tomsich 	const struct spi_clkreg *spiclk = NULL;
7238fa6979bSPhilipp Tomsich 	int src_clk_div;
7248fa6979bSPhilipp Tomsich 
725217273cdSKever Yang 	src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz) - 1;
726217273cdSKever Yang 	assert(src_clk_div < 128);
7278fa6979bSPhilipp Tomsich 
7288fa6979bSPhilipp Tomsich 	switch (clk_id) {
7298fa6979bSPhilipp Tomsich 	case SCLK_SPI1 ... SCLK_SPI5:
7308fa6979bSPhilipp Tomsich 		spiclk = &spi_clkregs[clk_id - SCLK_SPI0];
7318fa6979bSPhilipp Tomsich 		break;
7328fa6979bSPhilipp Tomsich 
7338fa6979bSPhilipp Tomsich 	default:
73490aa625cSMasahiro Yamada 		pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id);
7358fa6979bSPhilipp Tomsich 		return -EINVAL;
7368fa6979bSPhilipp Tomsich 	}
7378fa6979bSPhilipp Tomsich 
7388fa6979bSPhilipp Tomsich 	rk_clrsetreg(&cru->clksel_con[spiclk->reg],
7398fa6979bSPhilipp Tomsich 		     ((CLK_SPI_PLL_DIV_CON_MASK << spiclk->div_shift) |
7408fa6979bSPhilipp Tomsich 		       (CLK_SPI_PLL_SEL_GPLL << spiclk->sel_shift)),
7418fa6979bSPhilipp Tomsich 		     ((src_clk_div << spiclk->div_shift) |
7428fa6979bSPhilipp Tomsich 		      (CLK_SPI_PLL_SEL_GPLL << spiclk->sel_shift)));
7438fa6979bSPhilipp Tomsich 
744beb90a53SPhilipp Tomsich 	return rk3399_spi_get_clk(cru, clk_id);
7458fa6979bSPhilipp Tomsich }
7468fa6979bSPhilipp Tomsich 
7476bfdfc4fSElaine Zhang #define RK3399_LIMIT_PLL_ACLK_VOP	(400 * 1000000)
7486bfdfc4fSElaine Zhang 
rk3399_vop_set_clk(struct rk3399_cru * cru,ulong clk_id,u32 hz)749aff8795cSHeiko Stübner static ulong rk3399_vop_set_clk(struct rk3399_cru *cru, ulong clk_id, u32 hz)
750aff8795cSHeiko Stübner {
7516bfdfc4fSElaine Zhang 	struct pll_div vpll_config = {0}, cpll_config = {0};
7526bfdfc4fSElaine Zhang 	int aclk_vop = RK3399_LIMIT_PLL_ACLK_VOP;
753aff8795cSHeiko Stübner 	void *aclkreg_addr, *dclkreg_addr;
7546bfdfc4fSElaine Zhang 	u32 div = 1;
755aff8795cSHeiko Stübner 
756aff8795cSHeiko Stübner 	switch (clk_id) {
757aff8795cSHeiko Stübner 	case DCLK_VOP0:
758aff8795cSHeiko Stübner 		aclkreg_addr = &cru->clksel_con[47];
759aff8795cSHeiko Stübner 		dclkreg_addr = &cru->clksel_con[49];
760aff8795cSHeiko Stübner 		break;
761aff8795cSHeiko Stübner 	case DCLK_VOP1:
762aff8795cSHeiko Stübner 		aclkreg_addr = &cru->clksel_con[48];
763aff8795cSHeiko Stübner 		dclkreg_addr = &cru->clksel_con[50];
764aff8795cSHeiko Stübner 		break;
765aff8795cSHeiko Stübner 	default:
766aff8795cSHeiko Stübner 		return -EINVAL;
767aff8795cSHeiko Stübner 	}
768aff8795cSHeiko Stübner 	/* vop aclk source clk: cpll */
7696bfdfc4fSElaine Zhang 	div = GPLL_HZ / aclk_vop;
7705f42424bSLin Huang 	assert(div - 1 <= 31);
771aff8795cSHeiko Stübner 
772aff8795cSHeiko Stübner 	rk_clrsetreg(aclkreg_addr,
773aff8795cSHeiko Stübner 		     ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
7746bfdfc4fSElaine Zhang 		     ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT |
775aff8795cSHeiko Stübner 		     (div - 1) << ACLK_VOP_DIV_CON_SHIFT);
776*6cf98e2fSElaine Zhang 	rk_clrsetreg(&cru->clksel_con[42],
777*6cf98e2fSElaine Zhang 		     ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
778*6cf98e2fSElaine Zhang 		     ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT |
779*6cf98e2fSElaine Zhang 		     (div - 1) << ACLK_VOP_DIV_CON_SHIFT);
780aff8795cSHeiko Stübner 
7816bfdfc4fSElaine Zhang 	if (readl(dclkreg_addr) & DCLK_VOP_PLL_SEL_MASK) {
782c6c6283cSElaine Zhang 		if (pll_para_config(hz, &cpll_config))
7836bfdfc4fSElaine Zhang 			return -1;
7846bfdfc4fSElaine Zhang 		rkclk_set_pll(&cru->cpll_con[0], &cpll_config);
7856bfdfc4fSElaine Zhang 	} else {
786c6c6283cSElaine Zhang 		if (pll_para_config(hz, &vpll_config))
7876bfdfc4fSElaine Zhang 			return -1;
788aff8795cSHeiko Stübner 		rkclk_set_pll(&cru->vpll_con[0], &vpll_config);
7896bfdfc4fSElaine Zhang 	}
790aff8795cSHeiko Stübner 
791aff8795cSHeiko Stübner 	rk_clrsetreg(dclkreg_addr,
7926bfdfc4fSElaine Zhang 		     DCLK_VOP_DCLK_SEL_MASK | DCLK_VOP_DIV_CON_MASK,
793aff8795cSHeiko Stübner 		     DCLK_VOP_DCLK_SEL_DIVOUT << DCLK_VOP_DCLK_SEL_SHIFT |
794c6c6283cSElaine Zhang 		     (1 - 1) << DCLK_VOP_DIV_CON_SHIFT);
795aff8795cSHeiko Stübner 
796aff8795cSHeiko Stübner 	return hz;
797aff8795cSHeiko Stübner }
798aff8795cSHeiko Stübner 
rk3399_mmc_get_clk(struct rk3399_cru * cru,uint clk_id)799aff8795cSHeiko Stübner static ulong rk3399_mmc_get_clk(struct rk3399_cru *cru, uint clk_id)
800aff8795cSHeiko Stübner {
801aff8795cSHeiko Stübner 	u32 div, con;
802aff8795cSHeiko Stübner 
803aff8795cSHeiko Stübner 	switch (clk_id) {
804998c61aeSPhilipp Tomsich 	case HCLK_SDMMC:
805aff8795cSHeiko Stübner 	case SCLK_SDMMC:
806aff8795cSHeiko Stübner 		con = readl(&cru->clksel_con[16]);
8073a94d75dSKever Yang 		/* dwmmc controller have internal div 2 */
8083a94d75dSKever Yang 		div = 2;
809aff8795cSHeiko Stübner 		break;
810aff8795cSHeiko Stübner 	case SCLK_EMMC:
811b2a78faeSchenfen 		con = readl(&cru->clksel_con[22]);
8123a94d75dSKever Yang 		div = 1;
813aff8795cSHeiko Stübner 		break;
814aff8795cSHeiko Stübner 	default:
815aff8795cSHeiko Stübner 		return -EINVAL;
816aff8795cSHeiko Stübner 	}
817aff8795cSHeiko Stübner 
8183a94d75dSKever Yang 	div *= (con & CLK_EMMC_DIV_CON_MASK) >> CLK_EMMC_DIV_CON_SHIFT;
819fd4b2dc0SKever Yang 	if ((con & CLK_EMMC_PLL_MASK) >> CLK_EMMC_PLL_SHIFT
820fd4b2dc0SKever Yang 			== CLK_EMMC_PLL_SEL_24M)
8213a94d75dSKever Yang 		return DIV_TO_RATE(OSC_HZ, div);
822fd4b2dc0SKever Yang 	else
823aff8795cSHeiko Stübner 		return DIV_TO_RATE(GPLL_HZ, div);
824aff8795cSHeiko Stübner }
825aff8795cSHeiko Stübner 
rk3399_mmc_set_clk(struct rk3399_cru * cru,ulong clk_id,ulong set_rate)826aff8795cSHeiko Stübner static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
827aff8795cSHeiko Stübner 				ulong clk_id, ulong set_rate)
828aff8795cSHeiko Stübner {
829aff8795cSHeiko Stübner 	int src_clk_div;
830aff8795cSHeiko Stübner 	int aclk_emmc = 198*MHz;
831aff8795cSHeiko Stübner 
832aff8795cSHeiko Stübner 	switch (clk_id) {
833998c61aeSPhilipp Tomsich 	case HCLK_SDMMC:
834aff8795cSHeiko Stübner 	case SCLK_SDMMC:
835fd4b2dc0SKever Yang 		/* Select clk_sdmmc source from GPLL by default */
8363a94d75dSKever Yang 		/* mmc clock defaulg div 2 internal, provide double in cru */
8373a94d75dSKever Yang 		src_clk_div = DIV_ROUND_UP(GPLL_HZ / 2, set_rate);
838aff8795cSHeiko Stübner 
839217273cdSKever Yang 		if (src_clk_div > 128) {
840fd4b2dc0SKever Yang 			/* use 24MHz source for 400KHz clock */
8413a94d75dSKever Yang 			src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
842217273cdSKever Yang 			assert(src_clk_div - 1 < 128);
843fd4b2dc0SKever Yang 			rk_clrsetreg(&cru->clksel_con[16],
844fd4b2dc0SKever Yang 				     CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
845fd4b2dc0SKever Yang 				     CLK_EMMC_PLL_SEL_24M << CLK_EMMC_PLL_SHIFT |
846fd4b2dc0SKever Yang 				     (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
847fd4b2dc0SKever Yang 		} else {
848aff8795cSHeiko Stübner 			rk_clrsetreg(&cru->clksel_con[16],
849aff8795cSHeiko Stübner 				     CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
850aff8795cSHeiko Stübner 				     CLK_EMMC_PLL_SEL_GPLL << CLK_EMMC_PLL_SHIFT |
851aff8795cSHeiko Stübner 				     (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
852fd4b2dc0SKever Yang 		}
853aff8795cSHeiko Stübner 		break;
854aff8795cSHeiko Stübner 	case SCLK_EMMC:
855aff8795cSHeiko Stübner 		/* Select aclk_emmc source from GPLL */
856217273cdSKever Yang 		src_clk_div = DIV_ROUND_UP(GPLL_HZ , aclk_emmc);
857217273cdSKever Yang 		assert(src_clk_div - 1 < 32);
858aff8795cSHeiko Stübner 
859aff8795cSHeiko Stübner 		rk_clrsetreg(&cru->clksel_con[21],
860aff8795cSHeiko Stübner 			     ACLK_EMMC_PLL_SEL_MASK | ACLK_EMMC_DIV_CON_MASK,
861aff8795cSHeiko Stübner 			     ACLK_EMMC_PLL_SEL_GPLL << ACLK_EMMC_PLL_SEL_SHIFT |
862aff8795cSHeiko Stübner 			     (src_clk_div - 1) << ACLK_EMMC_DIV_CON_SHIFT);
863aff8795cSHeiko Stübner 
864aff8795cSHeiko Stübner 		/* Select clk_emmc source from GPLL too */
865217273cdSKever Yang 		src_clk_div = DIV_ROUND_UP(GPLL_HZ, set_rate);
866b2a78faeSchenfen 		if (src_clk_div > 128) {
867b2a78faeSchenfen 			/* use 24MHz source for 400KHz clock */
868b2a78faeSchenfen 			src_clk_div = DIV_ROUND_UP(OSC_HZ, set_rate);
869217273cdSKever Yang 			assert(src_clk_div - 1 < 128);
870b2a78faeSchenfen 			rk_clrsetreg(&cru->clksel_con[22],
871b2a78faeSchenfen 				     CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
872b2a78faeSchenfen 				     CLK_EMMC_PLL_SEL_24M << CLK_EMMC_PLL_SHIFT |
873b2a78faeSchenfen 				     (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
874b2a78faeSchenfen 		} else {
875aff8795cSHeiko Stübner 			rk_clrsetreg(&cru->clksel_con[22],
876aff8795cSHeiko Stübner 				     CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK,
877aff8795cSHeiko Stübner 				     CLK_EMMC_PLL_SEL_GPLL << CLK_EMMC_PLL_SHIFT |
878aff8795cSHeiko Stübner 				     (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT);
879b2a78faeSchenfen 		}
880aff8795cSHeiko Stübner 		break;
881aff8795cSHeiko Stübner 	default:
882aff8795cSHeiko Stübner 		return -EINVAL;
883aff8795cSHeiko Stübner 	}
884aff8795cSHeiko Stübner 	return rk3399_mmc_get_clk(cru, clk_id);
885aff8795cSHeiko Stübner }
886aff8795cSHeiko Stübner 
rk3399_gmac_set_clk(struct rk3399_cru * cru,ulong rate)8870ee68417SPhilipp Tomsich static ulong rk3399_gmac_set_clk(struct rk3399_cru *cru, ulong rate)
8880ee68417SPhilipp Tomsich {
8890ee68417SPhilipp Tomsich 	ulong ret;
8900ee68417SPhilipp Tomsich 
8910ee68417SPhilipp Tomsich 	/*
8920ee68417SPhilipp Tomsich 	 * The RGMII CLK can be derived either from an external "clkin"
8930ee68417SPhilipp Tomsich 	 * or can be generated from internally by a divider from SCLK_MAC.
8940ee68417SPhilipp Tomsich 	 */
8950ee68417SPhilipp Tomsich 	if (readl(&cru->clksel_con[19]) & BIT(4)) {
8960ee68417SPhilipp Tomsich 		/* An external clock will always generate the right rate... */
8970ee68417SPhilipp Tomsich 		ret = rate;
8980ee68417SPhilipp Tomsich 	} else {
8990ee68417SPhilipp Tomsich 		/*
9000ee68417SPhilipp Tomsich 		 * No platform uses an internal clock to date.
9010ee68417SPhilipp Tomsich 		 * Implement this once it becomes necessary and print an error
9020ee68417SPhilipp Tomsich 		 * if someone tries to use it (while it remains unimplemented).
9030ee68417SPhilipp Tomsich 		 */
9040ee68417SPhilipp Tomsich 		pr_err("%s: internal clock is UNIMPLEMENTED\n", __func__);
9050ee68417SPhilipp Tomsich 		ret = 0;
9060ee68417SPhilipp Tomsich 	}
9070ee68417SPhilipp Tomsich 
9080ee68417SPhilipp Tomsich 	return ret;
9090ee68417SPhilipp Tomsich }
9100ee68417SPhilipp Tomsich 
9115ae2fd97SKever Yang #define PMUSGRF_DDR_RGN_CON16 0xff330040
rk3399_ddr_set_clk(struct rk3399_cru * cru,ulong set_rate)9125ae2fd97SKever Yang static ulong rk3399_ddr_set_clk(struct rk3399_cru *cru,
9135ae2fd97SKever Yang 				ulong set_rate)
9145ae2fd97SKever Yang {
9155ae2fd97SKever Yang 	struct pll_div dpll_cfg;
9165ae2fd97SKever Yang 
9175ae2fd97SKever Yang 	/*  IC ECO bug, need to set this register */
9185ae2fd97SKever Yang 	writel(0xc000c000, PMUSGRF_DDR_RGN_CON16);
9195ae2fd97SKever Yang 
9205ae2fd97SKever Yang 	/*  clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */
9215ae2fd97SKever Yang 	switch (set_rate) {
92251c830f2SYouMin Chen 	case 50 * MHz:
92351c830f2SYouMin Chen 		dpll_cfg = (struct pll_div)
92451c830f2SYouMin Chen 		{.refdiv = 1, .fbdiv = 12, .postdiv1 = 3, .postdiv2 = 2};
92551c830f2SYouMin Chen 		break;
9265ae2fd97SKever Yang 	case 200 * MHz:
9275ae2fd97SKever Yang 		dpll_cfg = (struct pll_div)
9285ae2fd97SKever Yang 		{.refdiv = 1, .fbdiv = 50, .postdiv1 = 6, .postdiv2 = 1};
9295ae2fd97SKever Yang 		break;
9305ae2fd97SKever Yang 	case 300 * MHz:
9315ae2fd97SKever Yang 		dpll_cfg = (struct pll_div)
9325ae2fd97SKever Yang 		{.refdiv = 2, .fbdiv = 100, .postdiv1 = 4, .postdiv2 = 1};
9335ae2fd97SKever Yang 		break;
93451c830f2SYouMin Chen 	case 400 * MHz:
93551c830f2SYouMin Chen 		dpll_cfg = (struct pll_div)
93651c830f2SYouMin Chen 		{.refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1};
93751c830f2SYouMin Chen 		break;
9385ae2fd97SKever Yang 	case 666 * MHz:
9395ae2fd97SKever Yang 		dpll_cfg = (struct pll_div)
9405ae2fd97SKever Yang 		{.refdiv = 2, .fbdiv = 111, .postdiv1 = 2, .postdiv2 = 1};
9415ae2fd97SKever Yang 		break;
9425ae2fd97SKever Yang 	case 800 * MHz:
9435ae2fd97SKever Yang 		dpll_cfg = (struct pll_div)
9445ae2fd97SKever Yang 		{.refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1};
9455ae2fd97SKever Yang 		break;
9465ae2fd97SKever Yang 	case 933 * MHz:
9475ae2fd97SKever Yang 		dpll_cfg = (struct pll_div)
9485ae2fd97SKever Yang 		{.refdiv = 1, .fbdiv = 116, .postdiv1 = 3, .postdiv2 = 1};
9495ae2fd97SKever Yang 		break;
9505ae2fd97SKever Yang 	default:
95190aa625cSMasahiro Yamada 		pr_err("Unsupported SDRAM frequency!,%ld\n", set_rate);
9525ae2fd97SKever Yang 	}
9535ae2fd97SKever Yang 	rkclk_set_pll(&cru->dpll_con[0], &dpll_cfg);
9545ae2fd97SKever Yang 
9555ae2fd97SKever Yang 	return set_rate;
9565ae2fd97SKever Yang }
957e78991bfSDavid Wu 
rk3399_saradc_get_clk(struct rk3399_cru * cru)958e78991bfSDavid Wu static ulong rk3399_saradc_get_clk(struct rk3399_cru *cru)
959e78991bfSDavid Wu {
960e78991bfSDavid Wu 	u32 div, val;
961e78991bfSDavid Wu 
962e78991bfSDavid Wu 	val = readl(&cru->clksel_con[26]);
963e78991bfSDavid Wu 	div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT,
964e78991bfSDavid Wu 			       CLK_SARADC_DIV_CON_WIDTH);
965e78991bfSDavid Wu 
966e78991bfSDavid Wu 	return DIV_TO_RATE(OSC_HZ, div);
967e78991bfSDavid Wu }
968e78991bfSDavid Wu 
rk3399_saradc_set_clk(struct rk3399_cru * cru,uint hz)969e78991bfSDavid Wu static ulong rk3399_saradc_set_clk(struct rk3399_cru *cru, uint hz)
970e78991bfSDavid Wu {
971e78991bfSDavid Wu 	int src_clk_div;
972e78991bfSDavid Wu 
973e78991bfSDavid Wu 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1;
9745f42424bSLin Huang 	assert(src_clk_div <= 255);
975e78991bfSDavid Wu 
976e78991bfSDavid Wu 	rk_clrsetreg(&cru->clksel_con[26],
977e78991bfSDavid Wu 		     CLK_SARADC_DIV_CON_MASK,
978e78991bfSDavid Wu 		     src_clk_div << CLK_SARADC_DIV_CON_SHIFT);
979e78991bfSDavid Wu 
980e78991bfSDavid Wu 	return rk3399_saradc_get_clk(cru);
981e78991bfSDavid Wu }
982e78991bfSDavid Wu 
rk3399_tsadc_get_clk(struct rk3399_cru * cru)983cb3c37fcSElaine Zhang static ulong rk3399_tsadc_get_clk(struct rk3399_cru *cru)
984cb3c37fcSElaine Zhang {
985cb3c37fcSElaine Zhang 	u32 div, val;
986cb3c37fcSElaine Zhang 
987cb3c37fcSElaine Zhang 	val = readl(&cru->clksel_con[27]);
988cb3c37fcSElaine Zhang 	div = bitfield_extract(val, CLK_TSADC_SEL_SHIFT,
989cb3c37fcSElaine Zhang 			       10);
990cb3c37fcSElaine Zhang 
991cb3c37fcSElaine Zhang 	return DIV_TO_RATE(OSC_HZ, div);
992cb3c37fcSElaine Zhang }
993cb3c37fcSElaine Zhang 
rk3399_tsadc_set_clk(struct rk3399_cru * cru,uint hz)994cb3c37fcSElaine Zhang static ulong rk3399_tsadc_set_clk(struct rk3399_cru *cru, uint hz)
995cb3c37fcSElaine Zhang {
996cb3c37fcSElaine Zhang 	int src_clk_div;
997cb3c37fcSElaine Zhang 
998cb3c37fcSElaine Zhang 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1;
999cb3c37fcSElaine Zhang 	assert(src_clk_div <= 255);
1000cb3c37fcSElaine Zhang 
1001cb3c37fcSElaine Zhang 	rk_clrsetreg(&cru->clksel_con[27],
1002cb3c37fcSElaine Zhang 		     CLK_TSADC_DIV_CON_MASK | CLK_TSADC_SEL_MASK,
1003cb3c37fcSElaine Zhang 		     (CLK_TSADC_SEL_X24M << CLK_TSADC_SEL_SHIFT) |
1004cb3c37fcSElaine Zhang 		     (src_clk_div << CLK_TSADC_DIV_CON_SHIFT));
1005cb3c37fcSElaine Zhang 
1006cb3c37fcSElaine Zhang 	return rk3399_tsadc_get_clk(cru);
1007cb3c37fcSElaine Zhang }
1008cb3c37fcSElaine Zhang 
rk3399_crypto_get_clk(struct rk3399_clk_priv * priv,ulong clk_id)1009187d951bSElaine Zhang static ulong rk3399_crypto_get_clk(struct rk3399_clk_priv *priv, ulong clk_id)
1010187d951bSElaine Zhang {
1011187d951bSElaine Zhang 	struct rk3399_cru *cru = priv->cru;
1012187d951bSElaine Zhang 	u32 div, con, parent;
1013187d951bSElaine Zhang 
1014187d951bSElaine Zhang 	switch (clk_id) {
1015187d951bSElaine Zhang 	case SCLK_CRYPTO0:
1016187d951bSElaine Zhang 		con = readl(&cru->clksel_con[24]);
1017187d951bSElaine Zhang 		div = (con & CRYPTO0_DIV_MASK) >> CRYPTO0_DIV_SHIFT;
1018187d951bSElaine Zhang 		parent = GPLL_HZ;
1019187d951bSElaine Zhang 		break;
1020187d951bSElaine Zhang 	case SCLK_CRYPTO1:
1021187d951bSElaine Zhang 		con = readl(&cru->clksel_con[26]);
1022187d951bSElaine Zhang 		div = (con & CRYPTO1_DIV_MASK) >> CRYPTO1_DIV_SHIFT;
1023187d951bSElaine Zhang 		parent = GPLL_HZ;
1024187d951bSElaine Zhang 		break;
1025187d951bSElaine Zhang 	default:
1026187d951bSElaine Zhang 		return -ENOENT;
1027187d951bSElaine Zhang 	}
1028187d951bSElaine Zhang 
1029187d951bSElaine Zhang 	return DIV_TO_RATE(parent, div);
1030187d951bSElaine Zhang }
1031187d951bSElaine Zhang 
rk3399_crypto_set_clk(struct rk3399_clk_priv * priv,ulong clk_id,ulong hz)1032187d951bSElaine Zhang static ulong rk3399_crypto_set_clk(struct rk3399_clk_priv *priv, ulong clk_id,
1033187d951bSElaine Zhang 				   ulong hz)
1034187d951bSElaine Zhang {
1035187d951bSElaine Zhang 	struct rk3399_cru *cru = priv->cru;
1036187d951bSElaine Zhang 	int src_clk_div;
1037187d951bSElaine Zhang 
1038187d951bSElaine Zhang 	src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz);
1039187d951bSElaine Zhang 	assert(src_clk_div - 1 <= 31);
1040187d951bSElaine Zhang 
1041187d951bSElaine Zhang 	/*
1042187d951bSElaine Zhang 	 * select gpll as crypto clock source and
1043187d951bSElaine Zhang 	 * set up dependent divisors for crypto clocks.
1044187d951bSElaine Zhang 	 */
1045187d951bSElaine Zhang 	switch (clk_id) {
1046187d951bSElaine Zhang 	case SCLK_CRYPTO0:
1047187d951bSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[24],
1048187d951bSElaine Zhang 			     CRYPTO0_PLL_SEL_MASK | CRYPTO0_DIV_MASK,
1049187d951bSElaine Zhang 			     CRYPTO_PLL_SEL_GPLL << CRYPTO0_PLL_SEL_SHIFT |
1050187d951bSElaine Zhang 			     (src_clk_div - 1) << CRYPTO0_DIV_SHIFT);
1051187d951bSElaine Zhang 		break;
1052187d951bSElaine Zhang 	case SCLK_CRYPTO1:
1053187d951bSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[26],
1054187d951bSElaine Zhang 			     CRYPTO1_PLL_SEL_MASK | CRYPTO1_DIV_MASK,
1055187d951bSElaine Zhang 			     CRYPTO_PLL_SEL_GPLL << CRYPTO1_PLL_SEL_SHIFT |
1056187d951bSElaine Zhang 			     (src_clk_div - 1) << CRYPTO1_DIV_SHIFT);
1057187d951bSElaine Zhang 		break;
1058187d951bSElaine Zhang 	default:
1059187d951bSElaine Zhang 		printf("do not support this peri freq\n");
1060187d951bSElaine Zhang 		return -EINVAL;
1061187d951bSElaine Zhang 	}
1062187d951bSElaine Zhang 
1063187d951bSElaine Zhang 	return rk3399_crypto_get_clk(priv, clk_id);
1064187d951bSElaine Zhang }
10658b75ff34SElaine Zhang 
1066c3723ef3SJoseph Chen #ifndef CONFIG_SPL_BUILD
rk3399_peri_get_clk(struct rk3399_clk_priv * priv,ulong clk_id)10678b75ff34SElaine Zhang static ulong rk3399_peri_get_clk(struct rk3399_clk_priv *priv, ulong clk_id)
10688b75ff34SElaine Zhang {
10698b75ff34SElaine Zhang 	struct rk3399_cru *cru = priv->cru;
10708b75ff34SElaine Zhang 	u32 div, con, parent;
10718b75ff34SElaine Zhang 
10728b75ff34SElaine Zhang 	switch (clk_id) {
10738b75ff34SElaine Zhang 	case ACLK_PERIHP:
10748b75ff34SElaine Zhang 		con = readl(&cru->clksel_con[14]);
10758b75ff34SElaine Zhang 		div = (con & ACLK_PERIHP_DIV_CON_MASK) >>
10768b75ff34SElaine Zhang 		      ACLK_PERIHP_DIV_CON_SHIFT;
10778b75ff34SElaine Zhang 		parent = GPLL_HZ;
10788b75ff34SElaine Zhang 		break;
10798b75ff34SElaine Zhang 	case PCLK_PERIHP:
10808b75ff34SElaine Zhang 		con = readl(&cru->clksel_con[14]);
10818b75ff34SElaine Zhang 		div = (con & PCLK_PERIHP_DIV_CON_MASK) >>
10828b75ff34SElaine Zhang 		      PCLK_PERIHP_DIV_CON_SHIFT;
10838b75ff34SElaine Zhang 		parent = rk3399_peri_get_clk(priv, ACLK_PERIHP);
10848b75ff34SElaine Zhang 		break;
10858b75ff34SElaine Zhang 	case HCLK_PERIHP:
10868b75ff34SElaine Zhang 		con = readl(&cru->clksel_con[14]);
10878b75ff34SElaine Zhang 		div = (con & HCLK_PERIHP_DIV_CON_MASK) >>
10888b75ff34SElaine Zhang 		      HCLK_PERIHP_DIV_CON_SHIFT;
10898b75ff34SElaine Zhang 		parent = rk3399_peri_get_clk(priv, ACLK_PERIHP);
10908b75ff34SElaine Zhang 		break;
10918b75ff34SElaine Zhang 	case ACLK_PERILP0:
10928b75ff34SElaine Zhang 		con = readl(&cru->clksel_con[23]);
10938b75ff34SElaine Zhang 		div = (con & ACLK_PERILP0_DIV_CON_MASK) >>
10948b75ff34SElaine Zhang 		      ACLK_PERILP0_DIV_CON_SHIFT;
10958b75ff34SElaine Zhang 		parent = GPLL_HZ;
10968b75ff34SElaine Zhang 		break;
10978b75ff34SElaine Zhang 	case HCLK_PERILP0:
10988b75ff34SElaine Zhang 		con = readl(&cru->clksel_con[23]);
10998b75ff34SElaine Zhang 		div = (con & HCLK_PERILP0_DIV_CON_MASK) >>
11008b75ff34SElaine Zhang 		      HCLK_PERILP0_DIV_CON_SHIFT;
11018b75ff34SElaine Zhang 		parent = rk3399_peri_get_clk(priv, ACLK_PERILP0);
11028b75ff34SElaine Zhang 		break;
11038b75ff34SElaine Zhang 	case PCLK_PERILP0:
11048b75ff34SElaine Zhang 		con = readl(&cru->clksel_con[23]);
11058b75ff34SElaine Zhang 		div = (con & PCLK_PERILP0_DIV_CON_MASK) >>
11068b75ff34SElaine Zhang 		      PCLK_PERILP0_DIV_CON_SHIFT;
11078b75ff34SElaine Zhang 		parent = rk3399_peri_get_clk(priv, ACLK_PERILP0);
11088b75ff34SElaine Zhang 		break;
11098b75ff34SElaine Zhang 	case HCLK_PERILP1:
11108b75ff34SElaine Zhang 		con = readl(&cru->clksel_con[25]);
11118b75ff34SElaine Zhang 		div = (con & HCLK_PERILP1_DIV_CON_MASK) >>
11128b75ff34SElaine Zhang 		      HCLK_PERILP1_DIV_CON_SHIFT;
11138b75ff34SElaine Zhang 		parent = GPLL_HZ;
11148b75ff34SElaine Zhang 		break;
11158b75ff34SElaine Zhang 	case PCLK_PERILP1:
11168b75ff34SElaine Zhang 		con = readl(&cru->clksel_con[25]);
11178b75ff34SElaine Zhang 		div = (con & PCLK_PERILP1_DIV_CON_MASK) >>
11188b75ff34SElaine Zhang 		      PCLK_PERILP1_DIV_CON_SHIFT;
11198b75ff34SElaine Zhang 		parent = rk3399_peri_get_clk(priv, HCLK_PERILP1);
11208b75ff34SElaine Zhang 		break;
11218b75ff34SElaine Zhang 	default:
11228b75ff34SElaine Zhang 		return -ENOENT;
11238b75ff34SElaine Zhang 	}
11248b75ff34SElaine Zhang 
11258b75ff34SElaine Zhang 	return DIV_TO_RATE(parent, div);
11268b75ff34SElaine Zhang }
11278b75ff34SElaine Zhang 
rk3399_alive_get_clk(struct rk3399_clk_priv * priv)1128981ee0bdSElaine Zhang static ulong rk3399_alive_get_clk(struct rk3399_clk_priv *priv)
1129981ee0bdSElaine Zhang {
1130981ee0bdSElaine Zhang 	struct rk3399_cru *cru = priv->cru;
1131981ee0bdSElaine Zhang 	u32 div, con, parent;
1132981ee0bdSElaine Zhang 
1133981ee0bdSElaine Zhang 	con = readl(&cru->clksel_con[57]);
1134981ee0bdSElaine Zhang 	div = (con & PCLK_ALIVE_DIV_CON_MASK) >>
1135981ee0bdSElaine Zhang 	      PCLK_ALIVE_DIV_CON_SHIFT;
1136981ee0bdSElaine Zhang 	parent = GPLL_HZ;
1137981ee0bdSElaine Zhang 	return DIV_TO_RATE(parent, div);
1138981ee0bdSElaine Zhang }
1139187d951bSElaine Zhang #endif
1140187d951bSElaine Zhang 
rk3399_clk_get_rate(struct clk * clk)1141aff8795cSHeiko Stübner static ulong rk3399_clk_get_rate(struct clk *clk)
1142aff8795cSHeiko Stübner {
1143aff8795cSHeiko Stübner 	struct rk3399_clk_priv *priv = dev_get_priv(clk->dev);
1144aff8795cSHeiko Stübner 	ulong rate = 0;
1145aff8795cSHeiko Stübner 
1146aff8795cSHeiko Stübner 	switch (clk->id) {
11476bfdfc4fSElaine Zhang 	case PLL_APLLL:
11486bfdfc4fSElaine Zhang 	case PLL_APLLB:
11496bfdfc4fSElaine Zhang 	case PLL_DPLL:
11506bfdfc4fSElaine Zhang 	case PLL_CPLL:
11516bfdfc4fSElaine Zhang 	case PLL_GPLL:
11526bfdfc4fSElaine Zhang 	case PLL_NPLL:
11536bfdfc4fSElaine Zhang 	case PLL_VPLL:
11548b75ff34SElaine Zhang 		rate = rk3399_pll_get_rate(priv, clk->id);
11556bfdfc4fSElaine Zhang 		break;
1156998c61aeSPhilipp Tomsich 	case HCLK_SDMMC:
1157aff8795cSHeiko Stübner 	case SCLK_SDMMC:
1158aff8795cSHeiko Stübner 	case SCLK_EMMC:
1159aff8795cSHeiko Stübner 		rate = rk3399_mmc_get_clk(priv->cru, clk->id);
1160aff8795cSHeiko Stübner 		break;
1161aff8795cSHeiko Stübner 	case SCLK_I2C1:
1162aff8795cSHeiko Stübner 	case SCLK_I2C2:
1163aff8795cSHeiko Stübner 	case SCLK_I2C3:
1164aff8795cSHeiko Stübner 	case SCLK_I2C5:
1165aff8795cSHeiko Stübner 	case SCLK_I2C6:
1166aff8795cSHeiko Stübner 	case SCLK_I2C7:
1167aff8795cSHeiko Stübner 		rate = rk3399_i2c_get_clk(priv->cru, clk->id);
1168aff8795cSHeiko Stübner 		break;
11698fa6979bSPhilipp Tomsich 	case SCLK_SPI0...SCLK_SPI5:
11708fa6979bSPhilipp Tomsich 		rate = rk3399_spi_get_clk(priv->cru, clk->id);
11718fa6979bSPhilipp Tomsich 		break;
11728fa6979bSPhilipp Tomsich 	case SCLK_UART0:
1173e959b707SLin Huang 	case SCLK_UART1:
11748fa6979bSPhilipp Tomsich 	case SCLK_UART2:
1175e959b707SLin Huang 	case SCLK_UART3:
11768fa6979bSPhilipp Tomsich 		return 24000000;
1177ffc1fac5SPhilipp Tomsich 		break;
1178ffc1fac5SPhilipp Tomsich 	case PCLK_HDMI_CTRL:
1179ffc1fac5SPhilipp Tomsich 		break;
1180aff8795cSHeiko Stübner 	case DCLK_VOP0:
1181aff8795cSHeiko Stübner 	case DCLK_VOP1:
1182aff8795cSHeiko Stübner 		break;
1183a70feb46SPhilipp Tomsich 	case PCLK_EFUSE1024NS:
1184a70feb46SPhilipp Tomsich 		break;
1185e78991bfSDavid Wu 	case SCLK_SARADC:
1186e78991bfSDavid Wu 		rate = rk3399_saradc_get_clk(priv->cru);
1187e78991bfSDavid Wu 		break;
1188cb3c37fcSElaine Zhang 	case SCLK_TSADC:
1189cb3c37fcSElaine Zhang 		rate = rk3399_tsadc_get_clk(priv->cru);
1190cb3c37fcSElaine Zhang 		break;
1191187d951bSElaine Zhang 	case SCLK_CRYPTO0:
1192187d951bSElaine Zhang 	case SCLK_CRYPTO1:
1193187d951bSElaine Zhang 		rate = rk3399_crypto_get_clk(priv, clk->id);
1194187d951bSElaine Zhang 		break;
1195c3723ef3SJoseph Chen #ifndef CONFIG_SPL_BUILD
11968b75ff34SElaine Zhang 	case ACLK_PERIHP:
11978b75ff34SElaine Zhang 	case HCLK_PERIHP:
11988b75ff34SElaine Zhang 	case PCLK_PERIHP:
11998b75ff34SElaine Zhang 	case ACLK_PERILP0:
12008b75ff34SElaine Zhang 	case HCLK_PERILP0:
12018b75ff34SElaine Zhang 	case PCLK_PERILP0:
12028b75ff34SElaine Zhang 	case HCLK_PERILP1:
12038b75ff34SElaine Zhang 	case PCLK_PERILP1:
12048b75ff34SElaine Zhang 		rate = rk3399_peri_get_clk(priv, clk->id);
12058b75ff34SElaine Zhang 		break;
1206981ee0bdSElaine Zhang 	case PCLK_ALIVE:
1207981ee0bdSElaine Zhang 	case PCLK_WDT:
1208981ee0bdSElaine Zhang 		rate = rk3399_alive_get_clk(priv);
1209981ee0bdSElaine Zhang 		break;
1210187d951bSElaine Zhang #endif
1211aff8795cSHeiko Stübner 	default:
1212aff8795cSHeiko Stübner 		return -ENOENT;
1213aff8795cSHeiko Stübner 	}
1214aff8795cSHeiko Stübner 
1215aff8795cSHeiko Stübner 	return rate;
1216aff8795cSHeiko Stübner }
1217aff8795cSHeiko Stübner 
rk3399_clk_set_rate(struct clk * clk,ulong rate)1218aff8795cSHeiko Stübner static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
1219aff8795cSHeiko Stübner {
1220aff8795cSHeiko Stübner 	struct rk3399_clk_priv *priv = dev_get_priv(clk->dev);
1221aff8795cSHeiko Stübner 	ulong ret = 0;
1222aff8795cSHeiko Stübner 
1223aff8795cSHeiko Stübner 	switch (clk->id) {
1224aff8795cSHeiko Stübner 	case 0 ... 63:
1225aff8795cSHeiko Stübner 		return 0;
1226a6de9238SPhilipp Tomsich 
1227a6de9238SPhilipp Tomsich 	case ACLK_PERIHP:
1228a6de9238SPhilipp Tomsich 	case HCLK_PERIHP:
1229a6de9238SPhilipp Tomsich 	case PCLK_PERIHP:
1230a6de9238SPhilipp Tomsich 		return 0;
1231a6de9238SPhilipp Tomsich 
1232a6de9238SPhilipp Tomsich 	case ACLK_PERILP0:
1233a6de9238SPhilipp Tomsich 	case HCLK_PERILP0:
1234a6de9238SPhilipp Tomsich 	case PCLK_PERILP0:
1235a6de9238SPhilipp Tomsich 		return 0;
1236a6de9238SPhilipp Tomsich 
1237a6de9238SPhilipp Tomsich 	case ACLK_CCI:
1238a6de9238SPhilipp Tomsich 		return 0;
1239a6de9238SPhilipp Tomsich 
1240a6de9238SPhilipp Tomsich 	case HCLK_PERILP1:
1241a6de9238SPhilipp Tomsich 	case PCLK_PERILP1:
1242a6de9238SPhilipp Tomsich 		return 0;
1243a6de9238SPhilipp Tomsich 
1244998c61aeSPhilipp Tomsich 	case HCLK_SDMMC:
1245aff8795cSHeiko Stübner 	case SCLK_SDMMC:
1246aff8795cSHeiko Stübner 	case SCLK_EMMC:
1247aff8795cSHeiko Stübner 		ret = rk3399_mmc_set_clk(priv->cru, clk->id, rate);
1248aff8795cSHeiko Stübner 		break;
124965d83303SPhilipp Tomsich 	case SCLK_MAC:
12500ee68417SPhilipp Tomsich 		ret = rk3399_gmac_set_clk(priv->cru, rate);
125165d83303SPhilipp Tomsich 		break;
1252aff8795cSHeiko Stübner 	case SCLK_I2C1:
1253aff8795cSHeiko Stübner 	case SCLK_I2C2:
1254aff8795cSHeiko Stübner 	case SCLK_I2C3:
1255aff8795cSHeiko Stübner 	case SCLK_I2C5:
1256aff8795cSHeiko Stübner 	case SCLK_I2C6:
1257aff8795cSHeiko Stübner 	case SCLK_I2C7:
1258aff8795cSHeiko Stübner 		ret = rk3399_i2c_set_clk(priv->cru, clk->id, rate);
1259aff8795cSHeiko Stübner 		break;
12608fa6979bSPhilipp Tomsich 	case SCLK_SPI0...SCLK_SPI5:
12618fa6979bSPhilipp Tomsich 		ret = rk3399_spi_set_clk(priv->cru, clk->id, rate);
12628fa6979bSPhilipp Tomsich 		break;
1263ffc1fac5SPhilipp Tomsich 	case PCLK_HDMI_CTRL:
1264ffc1fac5SPhilipp Tomsich 	case PCLK_VIO_GRF:
1265ffc1fac5SPhilipp Tomsich 		/* the PCLK gates for video are enabled by default */
1266ffc1fac5SPhilipp Tomsich 		break;
1267aff8795cSHeiko Stübner 	case DCLK_VOP0:
1268aff8795cSHeiko Stübner 	case DCLK_VOP1:
12695e79f443SKever Yang 		ret = rk3399_vop_set_clk(priv->cru, clk->id, rate);
1270aff8795cSHeiko Stübner 		break;
12715ae2fd97SKever Yang 	case SCLK_DDRCLK:
12725ae2fd97SKever Yang 		ret = rk3399_ddr_set_clk(priv->cru, rate);
12735ae2fd97SKever Yang 		break;
1274a70feb46SPhilipp Tomsich 	case PCLK_EFUSE1024NS:
1275a70feb46SPhilipp Tomsich 		break;
1276e78991bfSDavid Wu 	case SCLK_SARADC:
1277e78991bfSDavid Wu 		ret = rk3399_saradc_set_clk(priv->cru, rate);
1278e78991bfSDavid Wu 		break;
1279cb3c37fcSElaine Zhang 	case SCLK_TSADC:
1280cb3c37fcSElaine Zhang 		ret = rk3399_tsadc_set_clk(priv->cru, rate);
1281cb3c37fcSElaine Zhang 		break;
1282187d951bSElaine Zhang 	case SCLK_CRYPTO0:
1283187d951bSElaine Zhang 	case SCLK_CRYPTO1:
1284187d951bSElaine Zhang 		ret = rk3399_crypto_set_clk(priv, clk->id, rate);
1285187d951bSElaine Zhang 		break;
1286aff8795cSHeiko Stübner 	default:
1287aff8795cSHeiko Stübner 		return -ENOENT;
1288aff8795cSHeiko Stübner 	}
1289aff8795cSHeiko Stübner 
1290aff8795cSHeiko Stübner 	return ret;
1291aff8795cSHeiko Stübner }
1292aff8795cSHeiko Stübner 
rk3399_gmac_set_parent(struct clk * clk,struct clk * parent)1293d2866b32SPhilipp Tomsich static int __maybe_unused rk3399_gmac_set_parent(struct clk *clk, struct clk *parent)
12940ee68417SPhilipp Tomsich {
12950ee68417SPhilipp Tomsich 	struct rk3399_clk_priv *priv = dev_get_priv(clk->dev);
12960ee68417SPhilipp Tomsich 	const char *clock_output_name;
12970ee68417SPhilipp Tomsich 	int ret;
12980ee68417SPhilipp Tomsich 
12990ee68417SPhilipp Tomsich 	/*
13000ee68417SPhilipp Tomsich 	 * If the requested parent is in the same clock-controller and
13010ee68417SPhilipp Tomsich 	 * the id is SCLK_MAC ("clk_gmac"), switch to the internal clock.
13020ee68417SPhilipp Tomsich 	 */
13030ee68417SPhilipp Tomsich 	if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC)) {
13040ee68417SPhilipp Tomsich 		debug("%s: switching RGMII to SCLK_MAC\n", __func__);
13050ee68417SPhilipp Tomsich 		rk_clrreg(&priv->cru->clksel_con[19], BIT(4));
13060ee68417SPhilipp Tomsich 		return 0;
13070ee68417SPhilipp Tomsich 	}
13080ee68417SPhilipp Tomsich 
13090ee68417SPhilipp Tomsich 	/*
13100ee68417SPhilipp Tomsich 	 * Otherwise, we need to check the clock-output-names of the
13110ee68417SPhilipp Tomsich 	 * requested parent to see if the requested id is "clkin_gmac".
13120ee68417SPhilipp Tomsich 	 */
13130ee68417SPhilipp Tomsich 	ret = dev_read_string_index(parent->dev, "clock-output-names",
13140ee68417SPhilipp Tomsich 				    parent->id, &clock_output_name);
13150ee68417SPhilipp Tomsich 	if (ret < 0)
13160ee68417SPhilipp Tomsich 		return -ENODATA;
13170ee68417SPhilipp Tomsich 
13180ee68417SPhilipp Tomsich 	/* If this is "clkin_gmac", switch to the external clock input */
13190ee68417SPhilipp Tomsich 	if (!strcmp(clock_output_name, "clkin_gmac")) {
13200ee68417SPhilipp Tomsich 		debug("%s: switching RGMII to CLKIN\n", __func__);
13210ee68417SPhilipp Tomsich 		rk_setreg(&priv->cru->clksel_con[19], BIT(4));
13220ee68417SPhilipp Tomsich 		return 0;
13230ee68417SPhilipp Tomsich 	}
13240ee68417SPhilipp Tomsich 
13250ee68417SPhilipp Tomsich 	return -EINVAL;
13260ee68417SPhilipp Tomsich }
13270ee68417SPhilipp Tomsich 
rk3399_dclk_vop_set_parent(struct clk * clk,struct clk * parent)13286bfdfc4fSElaine Zhang static int __maybe_unused rk3399_dclk_vop_set_parent(struct clk *clk,
13296bfdfc4fSElaine Zhang 						     struct clk *parent)
13306bfdfc4fSElaine Zhang {
13316bfdfc4fSElaine Zhang 	struct rk3399_clk_priv *priv = dev_get_priv(clk->dev);
13326bfdfc4fSElaine Zhang 	void *dclkreg_addr;
13336bfdfc4fSElaine Zhang 
13346bfdfc4fSElaine Zhang 	switch (clk->id) {
13356bfdfc4fSElaine Zhang 	case DCLK_VOP0_DIV:
13366bfdfc4fSElaine Zhang 		dclkreg_addr = &priv->cru->clksel_con[49];
13376bfdfc4fSElaine Zhang 		break;
13386bfdfc4fSElaine Zhang 	case DCLK_VOP1_DIV:
13396bfdfc4fSElaine Zhang 		dclkreg_addr = &priv->cru->clksel_con[50];
13406bfdfc4fSElaine Zhang 		break;
13416bfdfc4fSElaine Zhang 	default:
13426bfdfc4fSElaine Zhang 		return -EINVAL;
13436bfdfc4fSElaine Zhang 	}
13446bfdfc4fSElaine Zhang 	if (parent->id == PLL_CPLL) {
13456bfdfc4fSElaine Zhang 		rk_clrsetreg(dclkreg_addr, DCLK_VOP_PLL_SEL_MASK,
13466bfdfc4fSElaine Zhang 			     DCLK_VOP_PLL_SEL_CPLL << DCLK_VOP_PLL_SEL_SHIFT);
13476bfdfc4fSElaine Zhang 	} else {
13486bfdfc4fSElaine Zhang 		rk_clrsetreg(dclkreg_addr, DCLK_VOP_PLL_SEL_MASK,
13496bfdfc4fSElaine Zhang 			     DCLK_VOP_PLL_SEL_VPLL << DCLK_VOP_PLL_SEL_SHIFT);
13506bfdfc4fSElaine Zhang 	}
13516bfdfc4fSElaine Zhang 
13526bfdfc4fSElaine Zhang 	return 0;
13536bfdfc4fSElaine Zhang }
13546bfdfc4fSElaine Zhang 
rk3399_clk_set_parent(struct clk * clk,struct clk * parent)1355d2866b32SPhilipp Tomsich static int __maybe_unused rk3399_clk_set_parent(struct clk *clk, struct clk *parent)
13560ee68417SPhilipp Tomsich {
13570ee68417SPhilipp Tomsich 	switch (clk->id) {
13580ee68417SPhilipp Tomsich 	case SCLK_RMII_SRC:
13590ee68417SPhilipp Tomsich 		return rk3399_gmac_set_parent(clk, parent);
13606bfdfc4fSElaine Zhang 	case DCLK_VOP0_DIV:
13616bfdfc4fSElaine Zhang 	case DCLK_VOP1_DIV:
13626bfdfc4fSElaine Zhang 		return rk3399_dclk_vop_set_parent(clk, parent);
13630ee68417SPhilipp Tomsich 	}
13640ee68417SPhilipp Tomsich 
13650ee68417SPhilipp Tomsich 	debug("%s: unsupported clk %ld\n", __func__, clk->id);
13660ee68417SPhilipp Tomsich 	return -ENOENT;
13670ee68417SPhilipp Tomsich }
13680ee68417SPhilipp Tomsich 
rk3399_clk_enable(struct clk * clk)1369cce8d7cdSPhilipp Tomsich static int rk3399_clk_enable(struct clk *clk)
1370cce8d7cdSPhilipp Tomsich {
1371cce8d7cdSPhilipp Tomsich 	switch (clk->id) {
1372cce8d7cdSPhilipp Tomsich 	case HCLK_HOST0:
1373cce8d7cdSPhilipp Tomsich 	case HCLK_HOST0_ARB:
13740a3a50d6SWilliam Wu 	case SCLK_USBPHY0_480M_SRC:
1375cce8d7cdSPhilipp Tomsich 	case HCLK_HOST1:
1376cce8d7cdSPhilipp Tomsich 	case HCLK_HOST1_ARB:
13770a3a50d6SWilliam Wu 	case SCLK_USBPHY1_480M_SRC:
137845d1e0c8SFrank Wang 	case ACLK_USB3OTG1:
137945d1e0c8SFrank Wang 	case ACLK_USB3_GRF:
138045d1e0c8SFrank Wang 	case SCLK_USB3OTG1_REF:
138145d1e0c8SFrank Wang 	case SCLK_USB3OTG1_SUSPEND:
1382cce8d7cdSPhilipp Tomsich 		return 0;
1383cce8d7cdSPhilipp Tomsich 	}
1384cce8d7cdSPhilipp Tomsich 
1385cce8d7cdSPhilipp Tomsich 	debug("%s: unsupported clk %ld\n", __func__, clk->id);
1386cce8d7cdSPhilipp Tomsich 	return -ENOENT;
1387cce8d7cdSPhilipp Tomsich }
1388cce8d7cdSPhilipp Tomsich 
1389aff8795cSHeiko Stübner static struct clk_ops rk3399_clk_ops = {
1390aff8795cSHeiko Stübner 	.get_rate = rk3399_clk_get_rate,
1391aff8795cSHeiko Stübner 	.set_rate = rk3399_clk_set_rate,
1392d2866b32SPhilipp Tomsich #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
13930ee68417SPhilipp Tomsich 	.set_parent = rk3399_clk_set_parent,
1394d2866b32SPhilipp Tomsich #endif
1395cce8d7cdSPhilipp Tomsich 	.enable = rk3399_clk_enable,
1396aff8795cSHeiko Stübner };
1397aff8795cSHeiko Stübner 
rkclk_init(struct rk3399_cru * cru)1398cd5a540cSKever Yang static void rkclk_init(struct rk3399_cru *cru)
1399cd5a540cSKever Yang {
1400cd5a540cSKever Yang 	u32 aclk_div;
1401cd5a540cSKever Yang 	u32 hclk_div;
1402cd5a540cSKever Yang 	u32 pclk_div;
1403cd5a540cSKever Yang 
14048b75ff34SElaine Zhang 	rk3399_configure_cpu(cru, APLL_816_MHZ, CPU_CLUSTER_LITTLE);
1405243edbf9SJoseph Chen 	rk3399_configure_cpu(cru, APLL_816_MHZ, CPU_CLUSTER_BIG);
1406ccced9e1SLin Huang 
1407cd5a540cSKever Yang 	/*
1408cd5a540cSKever Yang 	 * some cru registers changed by bootrom, we'd better reset them to
1409cd5a540cSKever Yang 	 * reset/default values described in TRM to avoid confusion in kernel.
1410cd5a540cSKever Yang 	 * Please consider these three lines as a fix of bootrom bug.
1411cd5a540cSKever Yang 	 */
141209e1ca43SElaine Zhang 	if (rkclk_pll_get_rate(&cru->npll_con[0]) != NPLL_HZ)
141309e1ca43SElaine Zhang 		rkclk_set_pll(&cru->npll_con[0], &npll_init_cfg);
141409e1ca43SElaine Zhang 
141509e1ca43SElaine Zhang 	if (rkclk_pll_get_rate(&cru->gpll_con[0]) == GPLL_HZ)
141609e1ca43SElaine Zhang 		return;
141709e1ca43SElaine Zhang 
1418cd5a540cSKever Yang 	rk_clrsetreg(&cru->clksel_con[12], 0xffff, 0x4101);
1419cd5a540cSKever Yang 	rk_clrsetreg(&cru->clksel_con[19], 0xffff, 0x033f);
1420cd5a540cSKever Yang 	rk_clrsetreg(&cru->clksel_con[56], 0x0003, 0x0003);
1421cd5a540cSKever Yang 
1422cd5a540cSKever Yang 	/* configure perihp aclk, hclk, pclk */
14234897499eSElaine Zhang 	aclk_div = DIV_ROUND_UP(GPLL_HZ, PERIHP_ACLK_HZ) - 1;
1424cd5a540cSKever Yang 
1425cd5a540cSKever Yang 	hclk_div = PERIHP_ACLK_HZ / PERIHP_HCLK_HZ - 1;
142688c36f12SElaine Zhang 	assert((hclk_div + 1) * PERIHP_HCLK_HZ <=
14275f42424bSLin Huang 	       PERIHP_ACLK_HZ && (hclk_div <= 0x3));
1428cd5a540cSKever Yang 
1429cd5a540cSKever Yang 	pclk_div = PERIHP_ACLK_HZ / PERIHP_PCLK_HZ - 1;
143088c36f12SElaine Zhang 	assert((pclk_div + 1) * PERIHP_PCLK_HZ <=
14315f42424bSLin Huang 	       PERIHP_ACLK_HZ && (pclk_div <= 0x7));
1432cd5a540cSKever Yang 
1433cd5a540cSKever Yang 	rk_clrsetreg(&cru->clksel_con[14],
1434cd5a540cSKever Yang 		     PCLK_PERIHP_DIV_CON_MASK | HCLK_PERIHP_DIV_CON_MASK |
1435cd5a540cSKever Yang 		     ACLK_PERIHP_PLL_SEL_MASK | ACLK_PERIHP_DIV_CON_MASK,
1436cd5a540cSKever Yang 		     pclk_div << PCLK_PERIHP_DIV_CON_SHIFT |
1437cd5a540cSKever Yang 		     hclk_div << HCLK_PERIHP_DIV_CON_SHIFT |
1438cd5a540cSKever Yang 		     ACLK_PERIHP_PLL_SEL_GPLL << ACLK_PERIHP_PLL_SEL_SHIFT |
1439cd5a540cSKever Yang 		     aclk_div << ACLK_PERIHP_DIV_CON_SHIFT);
1440cd5a540cSKever Yang 
1441cd5a540cSKever Yang 	/* configure perilp0 aclk, hclk, pclk */
14424897499eSElaine Zhang 	aclk_div = DIV_ROUND_UP(GPLL_HZ, PERILP0_ACLK_HZ) - 1;
1443cd5a540cSKever Yang 
1444cd5a540cSKever Yang 	hclk_div = PERILP0_ACLK_HZ / PERILP0_HCLK_HZ - 1;
144588c36f12SElaine Zhang 	assert((hclk_div + 1) * PERILP0_HCLK_HZ <=
14465f42424bSLin Huang 	       PERILP0_ACLK_HZ && (hclk_div <= 0x3));
1447cd5a540cSKever Yang 
1448cd5a540cSKever Yang 	pclk_div = PERILP0_ACLK_HZ / PERILP0_PCLK_HZ - 1;
144988c36f12SElaine Zhang 	assert((pclk_div + 1) * PERILP0_PCLK_HZ <=
14505f42424bSLin Huang 	       PERILP0_ACLK_HZ && (pclk_div <= 0x7));
1451cd5a540cSKever Yang 
1452cd5a540cSKever Yang 	rk_clrsetreg(&cru->clksel_con[23],
1453cd5a540cSKever Yang 		     PCLK_PERILP0_DIV_CON_MASK | HCLK_PERILP0_DIV_CON_MASK |
1454cd5a540cSKever Yang 		     ACLK_PERILP0_PLL_SEL_MASK | ACLK_PERILP0_DIV_CON_MASK,
1455cd5a540cSKever Yang 		     pclk_div << PCLK_PERILP0_DIV_CON_SHIFT |
1456cd5a540cSKever Yang 		     hclk_div << HCLK_PERILP0_DIV_CON_SHIFT |
1457cd5a540cSKever Yang 		     ACLK_PERILP0_PLL_SEL_GPLL << ACLK_PERILP0_PLL_SEL_SHIFT |
1458cd5a540cSKever Yang 		     aclk_div << ACLK_PERILP0_DIV_CON_SHIFT);
1459cd5a540cSKever Yang 
1460cd5a540cSKever Yang 	/* perilp1 hclk select gpll as source */
14614897499eSElaine Zhang 	hclk_div = DIV_ROUND_UP(GPLL_HZ, PERILP1_HCLK_HZ) - 1;
146288c36f12SElaine Zhang 	assert((hclk_div + 1) * PERILP1_HCLK_HZ <=
14635f42424bSLin Huang 	       GPLL_HZ && (hclk_div <= 0x1f));
1464cd5a540cSKever Yang 
14651702a77fSLin Huang 	pclk_div = PERILP1_HCLK_HZ / PERILP1_PCLK_HZ - 1;
146688c36f12SElaine Zhang 	assert((pclk_div + 1) * PERILP1_PCLK_HZ <=
14675f42424bSLin Huang 	       PERILP1_HCLK_HZ && (pclk_div <= 0x7));
1468cd5a540cSKever Yang 
1469cd5a540cSKever Yang 	rk_clrsetreg(&cru->clksel_con[25],
1470cd5a540cSKever Yang 		     PCLK_PERILP1_DIV_CON_MASK | HCLK_PERILP1_DIV_CON_MASK |
1471cd5a540cSKever Yang 		     HCLK_PERILP1_PLL_SEL_MASK,
1472cd5a540cSKever Yang 		     pclk_div << PCLK_PERILP1_DIV_CON_SHIFT |
1473cd5a540cSKever Yang 		     hclk_div << HCLK_PERILP1_DIV_CON_SHIFT |
1474cd5a540cSKever Yang 		     HCLK_PERILP1_PLL_SEL_GPLL << HCLK_PERILP1_PLL_SEL_SHIFT);
14754897499eSElaine Zhang 
147609e1ca43SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[21],
147709e1ca43SElaine Zhang 		     ACLK_EMMC_PLL_SEL_MASK | ACLK_EMMC_DIV_CON_MASK,
147809e1ca43SElaine Zhang 		     ACLK_EMMC_PLL_SEL_GPLL << ACLK_EMMC_PLL_SEL_SHIFT |
147909e1ca43SElaine Zhang 		     (4 - 1) << ACLK_EMMC_DIV_CON_SHIFT);
148009e1ca43SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[22], 0x3f << 0, 7 << 0);
148109e1ca43SElaine Zhang 
1482e57a08e5SElaine Zhang 	/*
1483e57a08e5SElaine Zhang 	 * I2c MUx is in cpll by default, but cpll is for dclk_vop exclusive.
1484e57a08e5SElaine Zhang 	 * If dclk_vop set rate after i2c init, the CPLL changed,
1485e57a08e5SElaine Zhang 	 * but the i2c not perception, it will resulting the wrong
1486e57a08e5SElaine Zhang 	 * frequency of the i2c.
1487e57a08e5SElaine Zhang 	 * So set the i2c frequency according to the kernel configuration,
1488e57a08e5SElaine Zhang 	 * and Hang I2C on the GPLL.
1489e57a08e5SElaine Zhang 	 */
1490e57a08e5SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[61], I2C_CLK_REG_MASK(1),
1491e57a08e5SElaine Zhang 		     I2C_CLK_REG_VALUE(1, 4));
1492e57a08e5SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[62], I2C_CLK_REG_MASK(2),
1493e57a08e5SElaine Zhang 		     I2C_CLK_REG_VALUE(2, 4));
1494e57a08e5SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[63], I2C_CLK_REG_MASK(3),
1495e57a08e5SElaine Zhang 		     I2C_CLK_REG_VALUE(3, 4));
1496e57a08e5SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[61], I2C_CLK_REG_MASK(5),
1497e57a08e5SElaine Zhang 		     I2C_CLK_REG_VALUE(5, 4));
1498e57a08e5SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[62], I2C_CLK_REG_MASK(6),
1499e57a08e5SElaine Zhang 		     I2C_CLK_REG_VALUE(6, 4));
1500e57a08e5SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[63], I2C_CLK_REG_MASK(7),
1501e57a08e5SElaine Zhang 		     I2C_CLK_REG_VALUE(7, 4));
1502e57a08e5SElaine Zhang 
15034897499eSElaine Zhang 	rkclk_set_pll(&cru->gpll_con[0], &gpll_init_cfg);
1504cd5a540cSKever Yang }
1505cd5a540cSKever Yang 
rk3399_clk_probe(struct udevice * dev)1506aff8795cSHeiko Stübner static int rk3399_clk_probe(struct udevice *dev)
1507aff8795cSHeiko Stübner {
1508aff8795cSHeiko Stübner 	struct rk3399_clk_priv *priv = dev_get_priv(dev);
1509aff8795cSHeiko Stübner 
15105ae2fd97SKever Yang #if CONFIG_IS_ENABLED(OF_PLATDATA)
15115ae2fd97SKever Yang 	struct rk3399_clk_plat *plat = dev_get_platdata(dev);
1512aff8795cSHeiko Stübner 
1513a28bfcc3SSimon Glass 	priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
15145ae2fd97SKever Yang #endif
1515044bc79dSElaine Zhang 
1516044bc79dSElaine Zhang 	priv->sync_kernel = false;
1517044bc79dSElaine Zhang 	if (!priv->armlclk_enter_hz)
1518044bc79dSElaine Zhang 		priv->armlclk_enter_hz =
1519044bc79dSElaine Zhang 		rkclk_pll_get_rate(&priv->cru->apll_l_con[0]);
1520044bc79dSElaine Zhang 	if (!priv->armbclk_enter_hz)
1521044bc79dSElaine Zhang 		priv->armbclk_enter_hz =
1522044bc79dSElaine Zhang 		rkclk_pll_get_rate(&priv->cru->apll_b_con[0]);
15235ae2fd97SKever Yang 	rkclk_init(priv->cru);
1524044bc79dSElaine Zhang 	if (!priv->armlclk_init_hz)
1525044bc79dSElaine Zhang 		priv->armlclk_init_hz =
1526044bc79dSElaine Zhang 		rkclk_pll_get_rate(&priv->cru->apll_l_con[0]);
1527044bc79dSElaine Zhang 	if (!priv->armbclk_init_hz)
1528044bc79dSElaine Zhang 		priv->armbclk_init_hz =
1529044bc79dSElaine Zhang 		rkclk_pll_get_rate(&priv->cru->apll_b_con[0]);
1530e57a08e5SElaine Zhang 
1531aff8795cSHeiko Stübner 	return 0;
1532aff8795cSHeiko Stübner }
1533aff8795cSHeiko Stübner 
rk3399_clk_ofdata_to_platdata(struct udevice * dev)1534aff8795cSHeiko Stübner static int rk3399_clk_ofdata_to_platdata(struct udevice *dev)
1535aff8795cSHeiko Stübner {
15365ae2fd97SKever Yang #if !CONFIG_IS_ENABLED(OF_PLATDATA)
1537aff8795cSHeiko Stübner 	struct rk3399_clk_priv *priv = dev_get_priv(dev);
1538aff8795cSHeiko Stübner 
1539db4c0dc8SPhilipp Tomsich 	priv->cru = dev_read_addr_ptr(dev);
15405ae2fd97SKever Yang #endif
1541aff8795cSHeiko Stübner 	return 0;
1542aff8795cSHeiko Stübner }
1543aff8795cSHeiko Stübner 
rk3399_clk_bind(struct udevice * dev)1544aff8795cSHeiko Stübner static int rk3399_clk_bind(struct udevice *dev)
1545aff8795cSHeiko Stübner {
1546aff8795cSHeiko Stübner 	int ret;
15473d555d75SElaine Zhang 	struct udevice *sys_child, *sf_child;
1548fbdd1558SKever Yang 	struct sysreset_reg *priv;
15493d555d75SElaine Zhang 	struct softreset_reg *sf_priv;
1550aff8795cSHeiko Stübner 
1551aff8795cSHeiko Stübner 	/* The reset driver does not have a device node, so bind it here */
1552fbdd1558SKever Yang 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1553fbdd1558SKever Yang 				 &sys_child);
1554fbdd1558SKever Yang 	if (ret) {
1555fbdd1558SKever Yang 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1556fbdd1558SKever Yang 	} else {
1557fbdd1558SKever Yang 		priv = malloc(sizeof(struct sysreset_reg));
1558fbdd1558SKever Yang 		priv->glb_srst_fst_value = offsetof(struct rk3399_cru,
1559fbdd1558SKever Yang 						    glb_srst_fst_value);
1560fbdd1558SKever Yang 		priv->glb_srst_snd_value = offsetof(struct rk3399_cru,
1561fbdd1558SKever Yang 						    glb_srst_snd_value);
1562fbdd1558SKever Yang 		sys_child->priv = priv;
1563fbdd1558SKever Yang 	}
1564aff8795cSHeiko Stübner 
15653d555d75SElaine Zhang 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
15663d555d75SElaine Zhang 					 dev_ofnode(dev), &sf_child);
15673d555d75SElaine Zhang 	if (ret) {
15683d555d75SElaine Zhang 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
15693d555d75SElaine Zhang 	} else {
15703d555d75SElaine Zhang 		sf_priv = malloc(sizeof(struct softreset_reg));
15713d555d75SElaine Zhang 		sf_priv->sf_reset_offset = offsetof(struct rk3399_cru,
15723d555d75SElaine Zhang 						    softrst_con[0]);
15733d555d75SElaine Zhang 		sf_priv->sf_reset_num = 21;
15743d555d75SElaine Zhang 		sf_child->priv = sf_priv;
15753d555d75SElaine Zhang 	}
15763d555d75SElaine Zhang 
1577aff8795cSHeiko Stübner 	return 0;
1578aff8795cSHeiko Stübner }
1579aff8795cSHeiko Stübner 
1580aff8795cSHeiko Stübner static const struct udevice_id rk3399_clk_ids[] = {
1581aff8795cSHeiko Stübner 	{ .compatible = "rockchip,rk3399-cru" },
1582aff8795cSHeiko Stübner 	{ }
1583aff8795cSHeiko Stübner };
1584aff8795cSHeiko Stübner 
1585aff8795cSHeiko Stübner U_BOOT_DRIVER(clk_rk3399) = {
15865ae2fd97SKever Yang 	.name		= "rockchip_rk3399_cru",
1587aff8795cSHeiko Stübner 	.id		= UCLASS_CLK,
1588aff8795cSHeiko Stübner 	.of_match	= rk3399_clk_ids,
1589aff8795cSHeiko Stübner 	.priv_auto_alloc_size = sizeof(struct rk3399_clk_priv),
1590aff8795cSHeiko Stübner 	.ofdata_to_platdata = rk3399_clk_ofdata_to_platdata,
1591aff8795cSHeiko Stübner 	.ops		= &rk3399_clk_ops,
1592aff8795cSHeiko Stübner 	.bind		= rk3399_clk_bind,
1593aff8795cSHeiko Stübner 	.probe		= rk3399_clk_probe,
15945ae2fd97SKever Yang #if CONFIG_IS_ENABLED(OF_PLATDATA)
15955ae2fd97SKever Yang 	.platdata_auto_alloc_size = sizeof(struct rk3399_clk_plat),
15965ae2fd97SKever Yang #endif
1597aff8795cSHeiko Stübner };
15985e79f443SKever Yang 
rk3399_i2c_get_pmuclk(struct rk3399_pmucru * pmucru,ulong clk_id)15995e79f443SKever Yang static ulong rk3399_i2c_get_pmuclk(struct rk3399_pmucru *pmucru, ulong clk_id)
16005e79f443SKever Yang {
16015e79f443SKever Yang 	u32 div, con;
16025e79f443SKever Yang 
16035e79f443SKever Yang 	switch (clk_id) {
16045e79f443SKever Yang 	case SCLK_I2C0_PMU:
16055e79f443SKever Yang 		con = readl(&pmucru->pmucru_clksel[2]);
16065e79f443SKever Yang 		div = I2C_CLK_DIV_VALUE(con, 0);
16075e79f443SKever Yang 		break;
16085e79f443SKever Yang 	case SCLK_I2C4_PMU:
16095e79f443SKever Yang 		con = readl(&pmucru->pmucru_clksel[3]);
16105e79f443SKever Yang 		div = I2C_CLK_DIV_VALUE(con, 4);
16115e79f443SKever Yang 		break;
16125e79f443SKever Yang 	case SCLK_I2C8_PMU:
16135e79f443SKever Yang 		con = readl(&pmucru->pmucru_clksel[2]);
16145e79f443SKever Yang 		div = I2C_CLK_DIV_VALUE(con, 8);
16155e79f443SKever Yang 		break;
16165e79f443SKever Yang 	default:
16175e79f443SKever Yang 		printf("do not support this i2c bus\n");
16185e79f443SKever Yang 		return -EINVAL;
16195e79f443SKever Yang 	}
16205e79f443SKever Yang 
16215e79f443SKever Yang 	return DIV_TO_RATE(PPLL_HZ, div);
16225e79f443SKever Yang }
16235e79f443SKever Yang 
rk3399_i2c_set_pmuclk(struct rk3399_pmucru * pmucru,ulong clk_id,uint hz)16245e79f443SKever Yang static ulong rk3399_i2c_set_pmuclk(struct rk3399_pmucru *pmucru, ulong clk_id,
16255e79f443SKever Yang 				   uint hz)
16265e79f443SKever Yang {
16275e79f443SKever Yang 	int src_clk_div;
16285e79f443SKever Yang 
16295e79f443SKever Yang 	src_clk_div = PPLL_HZ / hz;
16305e79f443SKever Yang 	assert(src_clk_div - 1 < 127);
16315e79f443SKever Yang 
16325e79f443SKever Yang 	switch (clk_id) {
16335e79f443SKever Yang 	case SCLK_I2C0_PMU:
16345e79f443SKever Yang 		rk_clrsetreg(&pmucru->pmucru_clksel[2], I2C_PMUCLK_REG_MASK(0),
16355e79f443SKever Yang 			     I2C_PMUCLK_REG_VALUE(0, src_clk_div));
16365e79f443SKever Yang 		break;
16375e79f443SKever Yang 	case SCLK_I2C4_PMU:
16385e79f443SKever Yang 		rk_clrsetreg(&pmucru->pmucru_clksel[3], I2C_PMUCLK_REG_MASK(4),
16395e79f443SKever Yang 			     I2C_PMUCLK_REG_VALUE(4, src_clk_div));
16405e79f443SKever Yang 		break;
16415e79f443SKever Yang 	case SCLK_I2C8_PMU:
16425e79f443SKever Yang 		rk_clrsetreg(&pmucru->pmucru_clksel[2], I2C_PMUCLK_REG_MASK(8),
16435e79f443SKever Yang 			     I2C_PMUCLK_REG_VALUE(8, src_clk_div));
16445e79f443SKever Yang 		break;
16455e79f443SKever Yang 	default:
16465e79f443SKever Yang 		printf("do not support this i2c bus\n");
16475e79f443SKever Yang 		return -EINVAL;
16485e79f443SKever Yang 	}
16495e79f443SKever Yang 
16505e79f443SKever Yang 	return DIV_TO_RATE(PPLL_HZ, src_clk_div);
16515e79f443SKever Yang }
16525e79f443SKever Yang 
rk3399_pwm_get_clk(struct rk3399_pmucru * pmucru)16535e79f443SKever Yang static ulong rk3399_pwm_get_clk(struct rk3399_pmucru *pmucru)
16545e79f443SKever Yang {
16555e79f443SKever Yang 	u32 div, con;
16565e79f443SKever Yang 
16575e79f443SKever Yang 	/* PWM closk rate is same as pclk_pmu */
16585e79f443SKever Yang 	con = readl(&pmucru->pmucru_clksel[0]);
16595e79f443SKever Yang 	div = con & PMU_PCLK_DIV_CON_MASK;
16605e79f443SKever Yang 
16615e79f443SKever Yang 	return DIV_TO_RATE(PPLL_HZ, div);
16625e79f443SKever Yang }
16635e79f443SKever Yang 
rk3399_pmuclk_get_rate(struct clk * clk)16645e79f443SKever Yang static ulong rk3399_pmuclk_get_rate(struct clk *clk)
16655e79f443SKever Yang {
16665e79f443SKever Yang 	struct rk3399_pmuclk_priv *priv = dev_get_priv(clk->dev);
16675e79f443SKever Yang 	ulong rate = 0;
16685e79f443SKever Yang 
16695e79f443SKever Yang 	switch (clk->id) {
16705e79f443SKever Yang 	case PCLK_RKPWM_PMU:
1671981ee0bdSElaine Zhang 	case PCLK_WDT_M0_PMU:
16725e79f443SKever Yang 		rate = rk3399_pwm_get_clk(priv->pmucru);
16735e79f443SKever Yang 		break;
16745e79f443SKever Yang 	case SCLK_I2C0_PMU:
16755e79f443SKever Yang 	case SCLK_I2C4_PMU:
16765e79f443SKever Yang 	case SCLK_I2C8_PMU:
16775e79f443SKever Yang 		rate = rk3399_i2c_get_pmuclk(priv->pmucru, clk->id);
16785e79f443SKever Yang 		break;
1679e959b707SLin Huang 	case SCLK_UART4_PMU:
1680e959b707SLin Huang 		rate = 24000000;
1681e959b707SLin Huang 		break;
16825e79f443SKever Yang 	default:
16835e79f443SKever Yang 		return -ENOENT;
16845e79f443SKever Yang 	}
16855e79f443SKever Yang 
16865e79f443SKever Yang 	return rate;
16875e79f443SKever Yang }
16885e79f443SKever Yang 
rk3399_pmuclk_set_rate(struct clk * clk,ulong rate)16895e79f443SKever Yang static ulong rk3399_pmuclk_set_rate(struct clk *clk, ulong rate)
16905e79f443SKever Yang {
16915e79f443SKever Yang 	struct rk3399_pmuclk_priv *priv = dev_get_priv(clk->dev);
16925e79f443SKever Yang 	ulong ret = 0;
16935e79f443SKever Yang 
16945e79f443SKever Yang 	switch (clk->id) {
16955e79f443SKever Yang 	case SCLK_I2C0_PMU:
16965e79f443SKever Yang 	case SCLK_I2C4_PMU:
16975e79f443SKever Yang 	case SCLK_I2C8_PMU:
16985e79f443SKever Yang 		ret = rk3399_i2c_set_pmuclk(priv->pmucru, clk->id, rate);
16995e79f443SKever Yang 		break;
17005e79f443SKever Yang 	default:
17015e79f443SKever Yang 		return -ENOENT;
17025e79f443SKever Yang 	}
17035e79f443SKever Yang 
17045e79f443SKever Yang 	return ret;
17055e79f443SKever Yang }
17065e79f443SKever Yang 
17075e79f443SKever Yang static struct clk_ops rk3399_pmuclk_ops = {
17085e79f443SKever Yang 	.get_rate = rk3399_pmuclk_get_rate,
17095e79f443SKever Yang 	.set_rate = rk3399_pmuclk_set_rate,
17105e79f443SKever Yang };
17115e79f443SKever Yang 
17125ae2fd97SKever Yang #ifndef CONFIG_SPL_BUILD
pmuclk_init(struct rk3399_pmucru * pmucru)17135e79f443SKever Yang static void pmuclk_init(struct rk3399_pmucru *pmucru)
17145e79f443SKever Yang {
17155e79f443SKever Yang 	u32 pclk_div;
17165e79f443SKever Yang 
17175e79f443SKever Yang 	/*  configure pmu pll(ppll) */
17185e79f443SKever Yang 	rkclk_set_pll(&pmucru->ppll_con[0], &ppll_init_cfg);
17195e79f443SKever Yang 
17205e79f443SKever Yang 	/*  configure pmu pclk */
17215e79f443SKever Yang 	pclk_div = PPLL_HZ / PMU_PCLK_HZ - 1;
17225e79f443SKever Yang 	rk_clrsetreg(&pmucru->pmucru_clksel[0],
17235e79f443SKever Yang 		     PMU_PCLK_DIV_CON_MASK,
17245e79f443SKever Yang 		     pclk_div << PMU_PCLK_DIV_CON_SHIFT);
17255e79f443SKever Yang }
17265ae2fd97SKever Yang #endif
17275e79f443SKever Yang 
rk3399_pmuclk_probe(struct udevice * dev)17285e79f443SKever Yang static int rk3399_pmuclk_probe(struct udevice *dev)
17295e79f443SKever Yang {
173061dff33bSPhilipp Tomsich #if CONFIG_IS_ENABLED(OF_PLATDATA) || !defined(CONFIG_SPL_BUILD)
17315e79f443SKever Yang 	struct rk3399_pmuclk_priv *priv = dev_get_priv(dev);
173261dff33bSPhilipp Tomsich #endif
17335e79f443SKever Yang 
17345ae2fd97SKever Yang #if CONFIG_IS_ENABLED(OF_PLATDATA)
17355ae2fd97SKever Yang 	struct rk3399_pmuclk_plat *plat = dev_get_platdata(dev);
17365e79f443SKever Yang 
1737a28bfcc3SSimon Glass 	priv->pmucru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
17385ae2fd97SKever Yang #endif
17395ae2fd97SKever Yang 
17405ae2fd97SKever Yang #ifndef CONFIG_SPL_BUILD
17415ae2fd97SKever Yang 	pmuclk_init(priv->pmucru);
17425ae2fd97SKever Yang #endif
17435e79f443SKever Yang 	return 0;
17445e79f443SKever Yang }
17455e79f443SKever Yang 
rk3399_pmuclk_ofdata_to_platdata(struct udevice * dev)17465e79f443SKever Yang static int rk3399_pmuclk_ofdata_to_platdata(struct udevice *dev)
17475e79f443SKever Yang {
17485ae2fd97SKever Yang #if !CONFIG_IS_ENABLED(OF_PLATDATA)
17495e79f443SKever Yang 	struct rk3399_pmuclk_priv *priv = dev_get_priv(dev);
17505e79f443SKever Yang 
1751db4c0dc8SPhilipp Tomsich 	priv->pmucru = dev_read_addr_ptr(dev);
17525ae2fd97SKever Yang #endif
17535e79f443SKever Yang 	return 0;
17545e79f443SKever Yang }
17555e79f443SKever Yang 
rk3399_pmuclk_bind(struct udevice * dev)17563d555d75SElaine Zhang static int rk3399_pmuclk_bind(struct udevice *dev)
17573d555d75SElaine Zhang {
17583d555d75SElaine Zhang 	int ret = 0;
17593d555d75SElaine Zhang 	struct udevice *sf_child;
1760564ceaddSKever Yang 	struct softreset_reg *sf_priv;
17613d555d75SElaine Zhang 
17623d555d75SElaine Zhang 	ret = device_bind_driver_to_node(dev, "rockchip_reset",
17633d555d75SElaine Zhang 					 "reset", dev_ofnode(dev),
17643d555d75SElaine Zhang 					 &sf_child);
1765564ceaddSKever Yang 	if (ret) {
17663d555d75SElaine Zhang 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1767564ceaddSKever Yang 	} else {
1768564ceaddSKever Yang 		sf_priv = malloc(sizeof(struct softreset_reg));
17693d555d75SElaine Zhang 		sf_priv->sf_reset_offset = offsetof(struct rk3399_pmucru,
17703d555d75SElaine Zhang 						    pmucru_softrst_con[0]);
17713d555d75SElaine Zhang 		sf_priv->sf_reset_num = 2;
17723d555d75SElaine Zhang 		sf_child->priv = sf_priv;
1773564ceaddSKever Yang 	}
17743d555d75SElaine Zhang 
1775564ceaddSKever Yang 	return 0;
17763d555d75SElaine Zhang }
17773d555d75SElaine Zhang 
17785e79f443SKever Yang static const struct udevice_id rk3399_pmuclk_ids[] = {
17795e79f443SKever Yang 	{ .compatible = "rockchip,rk3399-pmucru" },
17805e79f443SKever Yang 	{ }
17815e79f443SKever Yang };
17825e79f443SKever Yang 
1783c8a6bc96SSimon Glass U_BOOT_DRIVER(rockchip_rk3399_pmuclk) = {
17845ae2fd97SKever Yang 	.name		= "rockchip_rk3399_pmucru",
17855e79f443SKever Yang 	.id		= UCLASS_CLK,
17865e79f443SKever Yang 	.of_match	= rk3399_pmuclk_ids,
17875e79f443SKever Yang 	.priv_auto_alloc_size = sizeof(struct rk3399_pmuclk_priv),
17885e79f443SKever Yang 	.ofdata_to_platdata = rk3399_pmuclk_ofdata_to_platdata,
17895e79f443SKever Yang 	.ops		= &rk3399_pmuclk_ops,
17905e79f443SKever Yang 	.probe		= rk3399_pmuclk_probe,
17913d555d75SElaine Zhang 	.bind		= rk3399_pmuclk_bind,
17925ae2fd97SKever Yang #if CONFIG_IS_ENABLED(OF_PLATDATA)
17935ae2fd97SKever Yang 	.platdata_auto_alloc_size = sizeof(struct rk3399_pmuclk_plat),
17945ae2fd97SKever Yang #endif
17955e79f443SKever Yang };
17968b75ff34SElaine Zhang 
17978b75ff34SElaine Zhang #ifndef CONFIG_SPL_BUILD
17988b75ff34SElaine Zhang /**
17998b75ff34SElaine Zhang  * soc_clk_dump() - Print clock frequencies
18008b75ff34SElaine Zhang  * Returns zero on success
18018b75ff34SElaine Zhang  *
18028b75ff34SElaine Zhang  * Implementation for the clk dump command.
18038b75ff34SElaine Zhang  */
soc_clk_dump(void)18048b75ff34SElaine Zhang int soc_clk_dump(void)
18058b75ff34SElaine Zhang {
18068b75ff34SElaine Zhang 	struct udevice *cru_dev, *pmucru_dev;
1807044bc79dSElaine Zhang 	struct rk3399_clk_priv *priv;
18088b75ff34SElaine Zhang 	const struct rk3399_clk_info *clk_dump;
18098b75ff34SElaine Zhang 	struct clk clk;
18108b75ff34SElaine Zhang 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
18118b75ff34SElaine Zhang 	unsigned long rate;
18128b75ff34SElaine Zhang 	int i, ret;
18138b75ff34SElaine Zhang 
18148b75ff34SElaine Zhang 	ret = uclass_get_device_by_driver(UCLASS_CLK,
18158b75ff34SElaine Zhang 					  DM_GET_DRIVER(clk_rk3399),
18168b75ff34SElaine Zhang 					  &cru_dev);
18178b75ff34SElaine Zhang 	if (ret) {
18188b75ff34SElaine Zhang 		printf("%s failed to get cru device\n", __func__);
18198b75ff34SElaine Zhang 		return ret;
18208b75ff34SElaine Zhang 	}
18218b75ff34SElaine Zhang 
18228b75ff34SElaine Zhang 	ret = uclass_get_device_by_driver(UCLASS_CLK,
18238b75ff34SElaine Zhang 					  DM_GET_DRIVER(rockchip_rk3399_pmuclk),
18248b75ff34SElaine Zhang 					  &pmucru_dev);
18258b75ff34SElaine Zhang 	if (ret) {
18268b75ff34SElaine Zhang 		printf("%s failed to get pmucru device\n", __func__);
18278b75ff34SElaine Zhang 		return ret;
18288b75ff34SElaine Zhang 	}
18298b75ff34SElaine Zhang 
1830044bc79dSElaine Zhang 	priv = dev_get_priv(cru_dev);
1831044bc79dSElaine Zhang 	printf("CLK: (%s. arml: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1832044bc79dSElaine Zhang 	       priv->sync_kernel ? "sync kernel" : "uboot",
1833044bc79dSElaine Zhang 	       priv->armlclk_enter_hz / 1000,
1834044bc79dSElaine Zhang 	       priv->armlclk_init_hz / 1000,
1835044bc79dSElaine Zhang 	       priv->set_armclk_rate ? priv->armlclk_hz / 1000 : 0,
1836044bc79dSElaine Zhang 	       priv->set_armclk_rate ? " KHz" : "N/A");
1837044bc79dSElaine Zhang 	printf("CLK: (%s. armb: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1838044bc79dSElaine Zhang 	       priv->sync_kernel ? "sync kernel" : "uboot",
1839044bc79dSElaine Zhang 	       priv->armbclk_enter_hz / 1000,
1840044bc79dSElaine Zhang 	       priv->armbclk_init_hz / 1000,
1841044bc79dSElaine Zhang 	       priv->set_armclk_rate ? priv->armbclk_hz / 1000 : 0,
1842044bc79dSElaine Zhang 	       priv->set_armclk_rate ? " KHz" : "N/A");
18438b75ff34SElaine Zhang 	for (i = 0; i < clk_count; i++) {
18448b75ff34SElaine Zhang 		clk_dump = &clks_dump[i];
18458b75ff34SElaine Zhang 		if (clk_dump->name) {
18468b75ff34SElaine Zhang 			clk.id = clk_dump->id;
18478b75ff34SElaine Zhang 			if (clk_dump->is_cru)
18488b75ff34SElaine Zhang 				ret = clk_request(cru_dev, &clk);
18498b75ff34SElaine Zhang 			else
18508b75ff34SElaine Zhang 				ret = clk_request(pmucru_dev, &clk);
18518b75ff34SElaine Zhang 			if (ret < 0)
18528b75ff34SElaine Zhang 				return ret;
18538b75ff34SElaine Zhang 
18548b75ff34SElaine Zhang 			rate = clk_get_rate(&clk);
18558b75ff34SElaine Zhang 			clk_free(&clk);
18568b75ff34SElaine Zhang 			if (i == 0) {
18578b75ff34SElaine Zhang 				if (rate < 0)
18588b75ff34SElaine Zhang 					printf("  %s %s\n", clk_dump->name,
18598b75ff34SElaine Zhang 					       "unknown");
18608b75ff34SElaine Zhang 				else
18618b75ff34SElaine Zhang 					printf("  %s %lu KHz\n", clk_dump->name,
18628b75ff34SElaine Zhang 					       rate / 1000);
18638b75ff34SElaine Zhang 			} else {
18648b75ff34SElaine Zhang 				if (rate < 0)
18658b75ff34SElaine Zhang 					printf("  %s %s\n", clk_dump->name,
18668b75ff34SElaine Zhang 					       "unknown");
18678b75ff34SElaine Zhang 				else
18688b75ff34SElaine Zhang 					printf("  %s %lu KHz\n", clk_dump->name,
18698b75ff34SElaine Zhang 					       rate / 1000);
18708b75ff34SElaine Zhang 			}
18718b75ff34SElaine Zhang 		}
18728b75ff34SElaine Zhang 	}
18738b75ff34SElaine Zhang 
18748b75ff34SElaine Zhang 	return 0;
18758b75ff34SElaine Zhang }
18768b75ff34SElaine Zhang #endif
1877