xref: /openbmc/u-boot/drivers/clk/rockchip/clk_rk3368.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
2d1dcf852SAndy Yan /*
3d1dcf852SAndy Yan  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
4d1dcf852SAndy Yan  * Author: Andy Yan <andy.yan@rock-chips.com>
5ddfe77dfSPhilipp Tomsich  * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
6d1dcf852SAndy Yan  */
7d1dcf852SAndy Yan 
8d1dcf852SAndy Yan #include <common.h>
9d1dcf852SAndy Yan #include <clk-uclass.h>
10d1dcf852SAndy Yan #include <dm.h>
11bee61801SPhilipp Tomsich #include <dt-structs.h>
12d1dcf852SAndy Yan #include <errno.h>
13bee61801SPhilipp Tomsich #include <mapmem.h>
14d1dcf852SAndy Yan #include <syscon.h>
15615514c1SDavid Wu #include <bitfield.h>
16d1dcf852SAndy Yan #include <asm/arch/clock.h>
17d1dcf852SAndy Yan #include <asm/arch/cru_rk3368.h>
18d1dcf852SAndy Yan #include <asm/arch/hardware.h>
19d1dcf852SAndy Yan #include <asm/io.h>
20d1dcf852SAndy Yan #include <dm/lists.h>
21d1dcf852SAndy Yan #include <dt-bindings/clock/rk3368-cru.h>
22d1dcf852SAndy Yan 
23bee61801SPhilipp Tomsich #if CONFIG_IS_ENABLED(OF_PLATDATA)
24bee61801SPhilipp Tomsich struct rk3368_clk_plat {
25bee61801SPhilipp Tomsich 	struct dtd_rockchip_rk3368_cru dtd;
26bee61801SPhilipp Tomsich };
27bee61801SPhilipp Tomsich #endif
28bee61801SPhilipp Tomsich 
29d1dcf852SAndy Yan struct pll_div {
30d1dcf852SAndy Yan 	u32 nr;
31d1dcf852SAndy Yan 	u32 nf;
32d1dcf852SAndy Yan 	u32 no;
33d1dcf852SAndy Yan };
34d1dcf852SAndy Yan 
35d1dcf852SAndy Yan #define OSC_HZ		(24 * 1000 * 1000)
36d1dcf852SAndy Yan #define APLL_L_HZ	(800 * 1000 * 1000)
37d1dcf852SAndy Yan #define APLL_B_HZ	(816 * 1000 * 1000)
38d1dcf852SAndy Yan #define GPLL_HZ		(576 * 1000 * 1000)
39d1dcf852SAndy Yan #define CPLL_HZ		(400 * 1000 * 1000)
40d1dcf852SAndy Yan 
41d1dcf852SAndy Yan #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
42d1dcf852SAndy Yan 
43d1dcf852SAndy Yan #define PLL_DIVISORS(hz, _nr, _no) { \
44d1dcf852SAndy Yan 	.nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no}; \
45d1dcf852SAndy Yan 	_Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\
46d1dcf852SAndy Yan 		       (_nr * _no) == hz, #hz "Hz cannot be hit with PLL " \
47d1dcf852SAndy Yan 		       "divisors on line " __stringify(__LINE__));
48d1dcf852SAndy Yan 
494bebf94eSPhilipp Tomsich #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
50d1dcf852SAndy Yan static const struct pll_div apll_l_init_cfg = PLL_DIVISORS(APLL_L_HZ, 12, 2);
51d1dcf852SAndy Yan static const struct pll_div apll_b_init_cfg = PLL_DIVISORS(APLL_B_HZ, 1, 2);
524bebf94eSPhilipp Tomsich #if !defined(CONFIG_TPL_BUILD)
53d1dcf852SAndy Yan static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 2);
54d1dcf852SAndy Yan static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 6);
554bebf94eSPhilipp Tomsich #endif
564bebf94eSPhilipp Tomsich #endif
57d1dcf852SAndy Yan 
58f5a43295SPhilipp Tomsich static ulong rk3368_clk_get_rate(struct clk *clk);
59f5a43295SPhilipp Tomsich 
60d1dcf852SAndy Yan /* Get pll rate by id */
rkclk_pll_get_rate(struct rk3368_cru * cru,enum rk3368_pll_id pll_id)61d1dcf852SAndy Yan static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru,
62d1dcf852SAndy Yan 				   enum rk3368_pll_id pll_id)
63d1dcf852SAndy Yan {
64d1dcf852SAndy Yan 	uint32_t nr, no, nf;
65d1dcf852SAndy Yan 	uint32_t con;
66d1dcf852SAndy Yan 	struct rk3368_pll *pll = &cru->pll[pll_id];
67d1dcf852SAndy Yan 
68d1dcf852SAndy Yan 	con = readl(&pll->con3);
69d1dcf852SAndy Yan 
70d1dcf852SAndy Yan 	switch ((con & PLL_MODE_MASK) >> PLL_MODE_SHIFT) {
71d1dcf852SAndy Yan 	case PLL_MODE_SLOW:
72d1dcf852SAndy Yan 		return OSC_HZ;
73d1dcf852SAndy Yan 	case PLL_MODE_NORMAL:
74d1dcf852SAndy Yan 		con = readl(&pll->con0);
75d1dcf852SAndy Yan 		no = ((con & PLL_OD_MASK) >> PLL_OD_SHIFT) + 1;
76d1dcf852SAndy Yan 		nr = ((con & PLL_NR_MASK) >> PLL_NR_SHIFT) + 1;
77d1dcf852SAndy Yan 		con = readl(&pll->con1);
78d1dcf852SAndy Yan 		nf = ((con & PLL_NF_MASK) >> PLL_NF_SHIFT) + 1;
79d1dcf852SAndy Yan 
80d1dcf852SAndy Yan 		return (24 * nf / (nr * no)) * 1000000;
81d1dcf852SAndy Yan 	case PLL_MODE_DEEP_SLOW:
82d1dcf852SAndy Yan 	default:
83d1dcf852SAndy Yan 		return 32768;
84d1dcf852SAndy Yan 	}
85d1dcf852SAndy Yan }
86d1dcf852SAndy Yan 
874bebf94eSPhilipp Tomsich #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
rkclk_set_pll(struct rk3368_cru * cru,enum rk3368_pll_id pll_id,const struct pll_div * div)88d1dcf852SAndy Yan static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id,
89ddfe77dfSPhilipp Tomsich 			 const struct pll_div *div)
90d1dcf852SAndy Yan {
91d1dcf852SAndy Yan 	struct rk3368_pll *pll = &cru->pll[pll_id];
92d1dcf852SAndy Yan 	/* All PLLs have same VCO and output frequency range restrictions*/
93d1dcf852SAndy Yan 	uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000;
94d1dcf852SAndy Yan 	uint output_hz = vco_hz / div->no;
95d1dcf852SAndy Yan 
96d1dcf852SAndy Yan 	debug("PLL at %p: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
97d1dcf852SAndy Yan 	      pll, div->nf, div->nr, div->no, vco_hz, output_hz);
98d1dcf852SAndy Yan 
99d1dcf852SAndy Yan 	/* enter slow mode and reset pll */
100d1dcf852SAndy Yan 	rk_clrsetreg(&pll->con3, PLL_MODE_MASK | PLL_RESET_MASK,
101d1dcf852SAndy Yan 		     PLL_RESET << PLL_RESET_SHIFT);
102d1dcf852SAndy Yan 
103d1dcf852SAndy Yan 	rk_clrsetreg(&pll->con0, PLL_NR_MASK | PLL_OD_MASK,
104d1dcf852SAndy Yan 		     ((div->nr - 1) << PLL_NR_SHIFT) |
105d1dcf852SAndy Yan 		     ((div->no - 1) << PLL_OD_SHIFT));
106d1dcf852SAndy Yan 	writel((div->nf - 1) << PLL_NF_SHIFT, &pll->con1);
107ddfe77dfSPhilipp Tomsich 	/*
108ddfe77dfSPhilipp Tomsich 	 * BWADJ should be set to NF / 2 to ensure the nominal bandwidth.
109ddfe77dfSPhilipp Tomsich 	 * Compare the RK3368 TRM, section "3.6.4 PLL Bandwidth Adjustment".
110ddfe77dfSPhilipp Tomsich 	 */
111ddfe77dfSPhilipp Tomsich 	clrsetbits_le32(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1);
112ddfe77dfSPhilipp Tomsich 
113d1dcf852SAndy Yan 	udelay(10);
114d1dcf852SAndy Yan 
115d1dcf852SAndy Yan 	/* return from reset */
116d1dcf852SAndy Yan 	rk_clrreg(&pll->con3, PLL_RESET_MASK);
117d1dcf852SAndy Yan 
118d1dcf852SAndy Yan 	/* waiting for pll lock */
119d1dcf852SAndy Yan 	while (!(readl(&pll->con1) & PLL_LOCK_STA))
120d1dcf852SAndy Yan 		udelay(1);
121d1dcf852SAndy Yan 
122d1dcf852SAndy Yan 	rk_clrsetreg(&pll->con3, PLL_MODE_MASK,
123d1dcf852SAndy Yan 		     PLL_MODE_NORMAL << PLL_MODE_SHIFT);
124d1dcf852SAndy Yan 
125d1dcf852SAndy Yan 	return 0;
126d1dcf852SAndy Yan }
1274bebf94eSPhilipp Tomsich #endif
128d1dcf852SAndy Yan 
1294bebf94eSPhilipp Tomsich #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
rkclk_init(struct rk3368_cru * cru)130d1dcf852SAndy Yan static void rkclk_init(struct rk3368_cru *cru)
131d1dcf852SAndy Yan {
132d1dcf852SAndy Yan 	u32 apllb, aplll, dpll, cpll, gpll;
133d1dcf852SAndy Yan 
134ddfe77dfSPhilipp Tomsich 	rkclk_set_pll(cru, APLLB, &apll_b_init_cfg);
135ddfe77dfSPhilipp Tomsich 	rkclk_set_pll(cru, APLLL, &apll_l_init_cfg);
1364bebf94eSPhilipp Tomsich #if !defined(CONFIG_TPL_BUILD)
1374bebf94eSPhilipp Tomsich 	/*
1384bebf94eSPhilipp Tomsich 	 * If we plan to return to the boot ROM, we can't increase the
1394bebf94eSPhilipp Tomsich 	 * GPLL rate from the SPL stage.
1404bebf94eSPhilipp Tomsich 	 */
141ddfe77dfSPhilipp Tomsich 	rkclk_set_pll(cru, GPLL, &gpll_init_cfg);
142ddfe77dfSPhilipp Tomsich 	rkclk_set_pll(cru, CPLL, &cpll_init_cfg);
1434bebf94eSPhilipp Tomsich #endif
144d1dcf852SAndy Yan 
145d1dcf852SAndy Yan 	apllb = rkclk_pll_get_rate(cru, APLLB);
146d1dcf852SAndy Yan 	aplll = rkclk_pll_get_rate(cru, APLLL);
147d1dcf852SAndy Yan 	dpll = rkclk_pll_get_rate(cru, DPLL);
148d1dcf852SAndy Yan 	cpll = rkclk_pll_get_rate(cru, CPLL);
149d1dcf852SAndy Yan 	gpll = rkclk_pll_get_rate(cru, GPLL);
150d1dcf852SAndy Yan 
151d1dcf852SAndy Yan 	debug("%s apllb(%d) apll(%d) dpll(%d) cpll(%d) gpll(%d)\n",
152d1dcf852SAndy Yan 	       __func__, apllb, aplll, dpll, cpll, gpll);
153d1dcf852SAndy Yan }
1544bebf94eSPhilipp Tomsich #endif
155d1dcf852SAndy Yan 
156f5a43295SPhilipp Tomsich #if !IS_ENABLED(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(MMC_SUPPORT)
rk3368_mmc_get_clk(struct rk3368_cru * cru,uint clk_id)157d1dcf852SAndy Yan static ulong rk3368_mmc_get_clk(struct rk3368_cru *cru, uint clk_id)
158d1dcf852SAndy Yan {
159d1dcf852SAndy Yan 	u32 div, con, con_id, rate;
160d1dcf852SAndy Yan 	u32 pll_rate;
161d1dcf852SAndy Yan 
162d1dcf852SAndy Yan 	switch (clk_id) {
163f5a43295SPhilipp Tomsich 	case HCLK_SDMMC:
164d1dcf852SAndy Yan 		con_id = 50;
165d1dcf852SAndy Yan 		break;
166f5a43295SPhilipp Tomsich 	case HCLK_EMMC:
167d1dcf852SAndy Yan 		con_id = 51;
168d1dcf852SAndy Yan 		break;
169d1dcf852SAndy Yan 	case SCLK_SDIO0:
170d1dcf852SAndy Yan 		con_id = 48;
171d1dcf852SAndy Yan 		break;
172d1dcf852SAndy Yan 	default:
173d1dcf852SAndy Yan 		return -EINVAL;
174d1dcf852SAndy Yan 	}
175d1dcf852SAndy Yan 
176d1dcf852SAndy Yan 	con = readl(&cru->clksel_con[con_id]);
177f5a43295SPhilipp Tomsich 	switch (con & MMC_PLL_SEL_MASK) {
178d1dcf852SAndy Yan 	case MMC_PLL_SEL_GPLL:
179d1dcf852SAndy Yan 		pll_rate = rkclk_pll_get_rate(cru, GPLL);
180d1dcf852SAndy Yan 		break;
181d1dcf852SAndy Yan 	case MMC_PLL_SEL_24M:
182d1dcf852SAndy Yan 		pll_rate = OSC_HZ;
183d1dcf852SAndy Yan 		break;
184d1dcf852SAndy Yan 	case MMC_PLL_SEL_CPLL:
185f5a43295SPhilipp Tomsich 		pll_rate = rkclk_pll_get_rate(cru, CPLL);
186f5a43295SPhilipp Tomsich 		break;
187d1dcf852SAndy Yan 	case MMC_PLL_SEL_USBPHY_480M:
188d1dcf852SAndy Yan 	default:
189d1dcf852SAndy Yan 		return -EINVAL;
190d1dcf852SAndy Yan 	}
191d1dcf852SAndy Yan 	div = (con & MMC_CLK_DIV_MASK) >> MMC_CLK_DIV_SHIFT;
192d1dcf852SAndy Yan 	rate = DIV_TO_RATE(pll_rate, div);
193d1dcf852SAndy Yan 
194f5a43295SPhilipp Tomsich 	debug("%s: raw rate %d (post-divide by 2)\n", __func__, rate);
195d1dcf852SAndy Yan 	return rate >> 1;
196d1dcf852SAndy Yan }
197d1dcf852SAndy Yan 
rk3368_mmc_find_best_rate_and_parent(struct clk * clk,ulong rate,u32 * best_mux,u32 * best_div)198f5a43295SPhilipp Tomsich static ulong rk3368_mmc_find_best_rate_and_parent(struct clk *clk,
199f5a43295SPhilipp Tomsich 						  ulong rate,
200f5a43295SPhilipp Tomsich 						  u32 *best_mux,
201f5a43295SPhilipp Tomsich 						  u32 *best_div)
202d1dcf852SAndy Yan {
203f5a43295SPhilipp Tomsich 	int i;
204f5a43295SPhilipp Tomsich 	ulong best_rate = 0;
205f5a43295SPhilipp Tomsich 	const ulong MHz = 1000000;
206f5a43295SPhilipp Tomsich 	const struct {
207f5a43295SPhilipp Tomsich 		u32 mux;
208f5a43295SPhilipp Tomsich 		ulong rate;
209f5a43295SPhilipp Tomsich 	} parents[] = {
210f5a43295SPhilipp Tomsich 		{ .mux = MMC_PLL_SEL_CPLL, .rate = CPLL_HZ },
211f5a43295SPhilipp Tomsich 		{ .mux = MMC_PLL_SEL_GPLL, .rate = GPLL_HZ },
212f5a43295SPhilipp Tomsich 		{ .mux = MMC_PLL_SEL_24M,  .rate = 24 * MHz }
213f5a43295SPhilipp Tomsich 	};
214d1dcf852SAndy Yan 
215f5a43295SPhilipp Tomsich 	debug("%s: target rate %ld\n", __func__, rate);
216f5a43295SPhilipp Tomsich 	for (i = 0; i < ARRAY_SIZE(parents); ++i) {
217f5a43295SPhilipp Tomsich 		/*
218f5a43295SPhilipp Tomsich 		 * Find the largest rate no larger than the target-rate for
219f5a43295SPhilipp Tomsich 		 * the current parent.
220f5a43295SPhilipp Tomsich 		 */
221f5a43295SPhilipp Tomsich 		ulong parent_rate = parents[i].rate;
222f5a43295SPhilipp Tomsich 		u32 div = DIV_ROUND_UP(parent_rate, rate);
223f5a43295SPhilipp Tomsich 		u32 adj_div = div;
224f5a43295SPhilipp Tomsich 		ulong new_rate = parent_rate / adj_div;
225f5a43295SPhilipp Tomsich 
226f5a43295SPhilipp Tomsich 		debug("%s: rate %ld, parent-mux %d, parent-rate %ld, div %d\n",
227f5a43295SPhilipp Tomsich 		      __func__, rate, parents[i].mux, parents[i].rate, div);
228f5a43295SPhilipp Tomsich 
229f5a43295SPhilipp Tomsich 		/* Skip, if not representable */
230f5a43295SPhilipp Tomsich 		if ((div - 1) > MMC_CLK_DIV_MASK)
231f5a43295SPhilipp Tomsich 			continue;
232f5a43295SPhilipp Tomsich 
233f5a43295SPhilipp Tomsich 		/* Skip, if we already have a better (or equal) solution */
234f5a43295SPhilipp Tomsich 		if (new_rate <= best_rate)
235f5a43295SPhilipp Tomsich 			continue;
236f5a43295SPhilipp Tomsich 
237f5a43295SPhilipp Tomsich 		/* This is our new best rate. */
238f5a43295SPhilipp Tomsich 		best_rate = new_rate;
239f5a43295SPhilipp Tomsich 		*best_mux = parents[i].mux;
240f5a43295SPhilipp Tomsich 		*best_div = div - 1;
241f5a43295SPhilipp Tomsich 	}
242f5a43295SPhilipp Tomsich 
243f5a43295SPhilipp Tomsich 	debug("%s: best_mux = %x, best_div = %d, best_rate = %ld\n",
244f5a43295SPhilipp Tomsich 	      __func__, *best_mux, *best_div, best_rate);
245f5a43295SPhilipp Tomsich 
246f5a43295SPhilipp Tomsich 	return best_rate;
247f5a43295SPhilipp Tomsich }
248f5a43295SPhilipp Tomsich 
rk3368_mmc_set_clk(struct clk * clk,ulong rate)249f5a43295SPhilipp Tomsich static ulong rk3368_mmc_set_clk(struct clk *clk, ulong rate)
250f5a43295SPhilipp Tomsich {
251f5a43295SPhilipp Tomsich 	struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
252f5a43295SPhilipp Tomsich 	struct rk3368_cru *cru = priv->cru;
253f5a43295SPhilipp Tomsich 	ulong clk_id = clk->id;
254f5a43295SPhilipp Tomsich 	u32 con_id, mux = 0, div = 0;
255f5a43295SPhilipp Tomsich 
256f5a43295SPhilipp Tomsich 	/* Find the best parent and rate */
257f5a43295SPhilipp Tomsich 	rk3368_mmc_find_best_rate_and_parent(clk, rate << 1, &mux, &div);
258d1dcf852SAndy Yan 
259d1dcf852SAndy Yan 	switch (clk_id) {
260f5a43295SPhilipp Tomsich 	case HCLK_SDMMC:
261d1dcf852SAndy Yan 		con_id = 50;
262d1dcf852SAndy Yan 		break;
263f5a43295SPhilipp Tomsich 	case HCLK_EMMC:
264d1dcf852SAndy Yan 		con_id = 51;
265d1dcf852SAndy Yan 		break;
266d1dcf852SAndy Yan 	case SCLK_SDIO0:
267d1dcf852SAndy Yan 		con_id = 48;
268d1dcf852SAndy Yan 		break;
269d1dcf852SAndy Yan 	default:
270d1dcf852SAndy Yan 		return -EINVAL;
271d1dcf852SAndy Yan 	}
272d1dcf852SAndy Yan 
273d1dcf852SAndy Yan 	rk_clrsetreg(&cru->clksel_con[con_id],
274d1dcf852SAndy Yan 		     MMC_PLL_SEL_MASK | MMC_CLK_DIV_MASK,
275f5a43295SPhilipp Tomsich 		     mux | div);
276d1dcf852SAndy Yan 
277d1dcf852SAndy Yan 	return rk3368_mmc_get_clk(cru, clk_id);
278d1dcf852SAndy Yan }
279f5a43295SPhilipp Tomsich #endif
280d1dcf852SAndy Yan 
28162924690SPhilipp Tomsich #if IS_ENABLED(CONFIG_TPL_BUILD)
rk3368_ddr_set_clk(struct rk3368_cru * cru,ulong set_rate)282a00dfa04SPhilipp Tomsich static ulong rk3368_ddr_set_clk(struct rk3368_cru *cru, ulong set_rate)
283a00dfa04SPhilipp Tomsich {
284a00dfa04SPhilipp Tomsich 	const struct pll_div *dpll_cfg = NULL;
285a00dfa04SPhilipp Tomsich 	const ulong MHz = 1000000;
286a00dfa04SPhilipp Tomsich 
287a00dfa04SPhilipp Tomsich 	/* Fout = ((Fin /NR) * NF )/ NO */
28862924690SPhilipp Tomsich 	static const struct pll_div dpll_1200 = PLL_DIVISORS(1200 * MHz, 1, 1);
28962924690SPhilipp Tomsich 	static const struct pll_div dpll_1332 =	PLL_DIVISORS(1332 * MHz, 2, 1);
29062924690SPhilipp Tomsich 	static const struct pll_div dpll_1600 =	PLL_DIVISORS(1600 * MHz, 3, 2);
291a00dfa04SPhilipp Tomsich 
292a00dfa04SPhilipp Tomsich 	switch (set_rate) {
293a00dfa04SPhilipp Tomsich 	case 1200*MHz:
294a00dfa04SPhilipp Tomsich 		dpll_cfg = &dpll_1200;
295a00dfa04SPhilipp Tomsich 		break;
296a00dfa04SPhilipp Tomsich 	case 1332*MHz:
297a00dfa04SPhilipp Tomsich 		dpll_cfg = &dpll_1332;
298a00dfa04SPhilipp Tomsich 		break;
299a00dfa04SPhilipp Tomsich 	case 1600*MHz:
300a00dfa04SPhilipp Tomsich 		dpll_cfg = &dpll_1600;
301a00dfa04SPhilipp Tomsich 		break;
302a00dfa04SPhilipp Tomsich 	default:
3039b643e31SMasahiro Yamada 		pr_err("Unsupported SDRAM frequency!,%ld\n", set_rate);
304a00dfa04SPhilipp Tomsich 	}
305a00dfa04SPhilipp Tomsich 	rkclk_set_pll(cru, DPLL, dpll_cfg);
306a00dfa04SPhilipp Tomsich 
307a00dfa04SPhilipp Tomsich 	return set_rate;
308a00dfa04SPhilipp Tomsich }
30962924690SPhilipp Tomsich #endif
310a00dfa04SPhilipp Tomsich 
311df0ae000SPhilipp Tomsich #if CONFIG_IS_ENABLED(GMAC_ROCKCHIP)
rk3368_gmac_set_clk(struct rk3368_cru * cru,ulong set_rate)31264a12202SDavid Wu static ulong rk3368_gmac_set_clk(struct rk3368_cru *cru, ulong set_rate)
313df0ae000SPhilipp Tomsich {
31464a12202SDavid Wu 	ulong ret;
31564a12202SDavid Wu 
316df0ae000SPhilipp Tomsich 	/*
31764a12202SDavid Wu 	 * The gmac clock can be derived either from an external clock
31864a12202SDavid Wu 	 * or can be generated from internally by a divider from SCLK_MAC.
319df0ae000SPhilipp Tomsich 	 */
32064a12202SDavid Wu 	if (readl(&cru->clksel_con[43]) & GMAC_MUX_SEL_EXTCLK) {
32164a12202SDavid Wu 		/* An external clock will always generate the right rate... */
32264a12202SDavid Wu 		ret = set_rate;
32364a12202SDavid Wu 	} else {
32464a12202SDavid Wu 		u32 con = readl(&cru->clksel_con[43]);
32564a12202SDavid Wu 		ulong pll_rate;
32664a12202SDavid Wu 		u8 div;
32764a12202SDavid Wu 
32864a12202SDavid Wu 		if (((con >> GMAC_PLL_SHIFT) & GMAC_PLL_MASK) ==
32964a12202SDavid Wu 		    GMAC_PLL_SELECT_GENERAL)
33064a12202SDavid Wu 			pll_rate = GPLL_HZ;
33164a12202SDavid Wu 		else if (((con >> GMAC_PLL_SHIFT) & GMAC_PLL_MASK) ==
33264a12202SDavid Wu 			 GMAC_PLL_SELECT_CODEC)
33364a12202SDavid Wu 			pll_rate = CPLL_HZ;
33464a12202SDavid Wu 		else
33564a12202SDavid Wu 			/* CPLL is not set */
33664a12202SDavid Wu 			return -EPERM;
33764a12202SDavid Wu 
33864a12202SDavid Wu 		div = DIV_ROUND_UP(pll_rate, set_rate) - 1;
33964a12202SDavid Wu 		if (div <= 0x1f)
34064a12202SDavid Wu 			rk_clrsetreg(&cru->clksel_con[43], GMAC_DIV_CON_MASK,
34164a12202SDavid Wu 				     div << GMAC_DIV_CON_SHIFT);
34264a12202SDavid Wu 		else
34364a12202SDavid Wu 			debug("Unsupported div for gmac:%d\n", div);
34464a12202SDavid Wu 
34564a12202SDavid Wu 		return DIV_TO_RATE(pll_rate, div);
34664a12202SDavid Wu 	}
34764a12202SDavid Wu 
34864a12202SDavid Wu 	return ret;
349df0ae000SPhilipp Tomsich }
350df0ae000SPhilipp Tomsich #endif
351df0ae000SPhilipp Tomsich 
352cf8aceb1SPhilipp Tomsich /*
353cf8aceb1SPhilipp Tomsich  * RK3368 SPI clocks have a common divider-width (7 bits) and a single bit
354cf8aceb1SPhilipp Tomsich  * to select either CPLL or GPLL as the clock-parent. The location within
355cf8aceb1SPhilipp Tomsich  * the enclosing CLKSEL_CON (i.e. div_shift and sel_shift) are variable.
356cf8aceb1SPhilipp Tomsich  */
357cf8aceb1SPhilipp Tomsich 
358cf8aceb1SPhilipp Tomsich struct spi_clkreg {
359cf8aceb1SPhilipp Tomsich 	uint8_t reg;  /* CLKSEL_CON[reg] register in CRU */
360cf8aceb1SPhilipp Tomsich 	uint8_t div_shift;
361cf8aceb1SPhilipp Tomsich 	uint8_t sel_shift;
362cf8aceb1SPhilipp Tomsich };
363cf8aceb1SPhilipp Tomsich 
364cf8aceb1SPhilipp Tomsich /*
365cf8aceb1SPhilipp Tomsich  * The entries are numbered relative to their offset from SCLK_SPI0.
366cf8aceb1SPhilipp Tomsich  */
367cf8aceb1SPhilipp Tomsich static const struct spi_clkreg spi_clkregs[] = {
368cf8aceb1SPhilipp Tomsich 	[0] = { .reg = 45, .div_shift = 0, .sel_shift = 7, },
369cf8aceb1SPhilipp Tomsich 	[1] = { .reg = 45, .div_shift = 8, .sel_shift = 15, },
370cf8aceb1SPhilipp Tomsich 	[2] = { .reg = 46, .div_shift = 8, .sel_shift = 15, },
371cf8aceb1SPhilipp Tomsich };
372cf8aceb1SPhilipp Tomsich 
extract_bits(u32 val,unsigned width,unsigned shift)373cf8aceb1SPhilipp Tomsich static inline u32 extract_bits(u32 val, unsigned width, unsigned shift)
374cf8aceb1SPhilipp Tomsich {
375cf8aceb1SPhilipp Tomsich 	return (val >> shift) & ((1 << width) - 1);
376cf8aceb1SPhilipp Tomsich }
377cf8aceb1SPhilipp Tomsich 
rk3368_spi_get_clk(struct rk3368_cru * cru,ulong clk_id)378cf8aceb1SPhilipp Tomsich static ulong rk3368_spi_get_clk(struct rk3368_cru *cru, ulong clk_id)
379cf8aceb1SPhilipp Tomsich {
380cf8aceb1SPhilipp Tomsich 	const struct spi_clkreg *spiclk = NULL;
381cf8aceb1SPhilipp Tomsich 	u32 div, val;
382cf8aceb1SPhilipp Tomsich 
383cf8aceb1SPhilipp Tomsich 	switch (clk_id) {
384cf8aceb1SPhilipp Tomsich 	case SCLK_SPI0 ... SCLK_SPI2:
385cf8aceb1SPhilipp Tomsich 		spiclk = &spi_clkregs[clk_id - SCLK_SPI0];
386cf8aceb1SPhilipp Tomsich 		break;
387cf8aceb1SPhilipp Tomsich 
388cf8aceb1SPhilipp Tomsich 	default:
3899b643e31SMasahiro Yamada 		pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id);
390cf8aceb1SPhilipp Tomsich 		return -EINVAL;
391cf8aceb1SPhilipp Tomsich 	}
392cf8aceb1SPhilipp Tomsich 
393cf8aceb1SPhilipp Tomsich 	val = readl(&cru->clksel_con[spiclk->reg]);
394cf8aceb1SPhilipp Tomsich 	div = extract_bits(val, 7, spiclk->div_shift);
395cf8aceb1SPhilipp Tomsich 
396cf8aceb1SPhilipp Tomsich 	debug("%s: div 0x%x\n", __func__, div);
397cf8aceb1SPhilipp Tomsich 	return DIV_TO_RATE(GPLL_HZ, div);
398cf8aceb1SPhilipp Tomsich }
399cf8aceb1SPhilipp Tomsich 
rk3368_spi_set_clk(struct rk3368_cru * cru,ulong clk_id,uint hz)400cf8aceb1SPhilipp Tomsich static ulong rk3368_spi_set_clk(struct rk3368_cru *cru, ulong clk_id, uint hz)
401cf8aceb1SPhilipp Tomsich {
402cf8aceb1SPhilipp Tomsich 	const struct spi_clkreg *spiclk = NULL;
403cf8aceb1SPhilipp Tomsich 	int src_clk_div;
404cf8aceb1SPhilipp Tomsich 
405cf8aceb1SPhilipp Tomsich 	src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz);
406cf8aceb1SPhilipp Tomsich 	assert(src_clk_div < 127);
407cf8aceb1SPhilipp Tomsich 
408cf8aceb1SPhilipp Tomsich 	switch (clk_id) {
409cf8aceb1SPhilipp Tomsich 	case SCLK_SPI0 ... SCLK_SPI2:
410cf8aceb1SPhilipp Tomsich 		spiclk = &spi_clkregs[clk_id - SCLK_SPI0];
411cf8aceb1SPhilipp Tomsich 		break;
412cf8aceb1SPhilipp Tomsich 
413cf8aceb1SPhilipp Tomsich 	default:
4149b643e31SMasahiro Yamada 		pr_err("%s: SPI clk-id %ld not supported\n", __func__, clk_id);
415cf8aceb1SPhilipp Tomsich 		return -EINVAL;
416cf8aceb1SPhilipp Tomsich 	}
417cf8aceb1SPhilipp Tomsich 
418cf8aceb1SPhilipp Tomsich 	rk_clrsetreg(&cru->clksel_con[spiclk->reg],
419cf8aceb1SPhilipp Tomsich 		     ((0x7f << spiclk->div_shift) |
420cf8aceb1SPhilipp Tomsich 		      (0x1 << spiclk->sel_shift)),
421cf8aceb1SPhilipp Tomsich 		     ((src_clk_div << spiclk->div_shift) |
422cf8aceb1SPhilipp Tomsich 		      (1 << spiclk->sel_shift)));
423cf8aceb1SPhilipp Tomsich 
424cf8aceb1SPhilipp Tomsich 	return rk3368_spi_get_clk(cru, clk_id);
425cf8aceb1SPhilipp Tomsich }
426cf8aceb1SPhilipp Tomsich 
rk3368_saradc_get_clk(struct rk3368_cru * cru)427615514c1SDavid Wu static ulong rk3368_saradc_get_clk(struct rk3368_cru *cru)
428615514c1SDavid Wu {
429615514c1SDavid Wu 	u32 div, val;
430615514c1SDavid Wu 
431615514c1SDavid Wu 	val = readl(&cru->clksel_con[25]);
432615514c1SDavid Wu 	div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT,
433615514c1SDavid Wu 			       CLK_SARADC_DIV_CON_WIDTH);
434615514c1SDavid Wu 
435615514c1SDavid Wu 	return DIV_TO_RATE(OSC_HZ, div);
436615514c1SDavid Wu }
437615514c1SDavid Wu 
rk3368_saradc_set_clk(struct rk3368_cru * cru,uint hz)438615514c1SDavid Wu static ulong rk3368_saradc_set_clk(struct rk3368_cru *cru, uint hz)
439615514c1SDavid Wu {
440615514c1SDavid Wu 	int src_clk_div;
441615514c1SDavid Wu 
442615514c1SDavid Wu 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1;
443615514c1SDavid Wu 	assert(src_clk_div < 128);
444615514c1SDavid Wu 
445615514c1SDavid Wu 	rk_clrsetreg(&cru->clksel_con[25],
446615514c1SDavid Wu 		     CLK_SARADC_DIV_CON_MASK,
447615514c1SDavid Wu 		     src_clk_div << CLK_SARADC_DIV_CON_SHIFT);
448615514c1SDavid Wu 
449615514c1SDavid Wu 	return rk3368_saradc_get_clk(cru);
450615514c1SDavid Wu }
451615514c1SDavid Wu 
rk3368_clk_get_rate(struct clk * clk)452cf8aceb1SPhilipp Tomsich static ulong rk3368_clk_get_rate(struct clk *clk)
453cf8aceb1SPhilipp Tomsich {
454cf8aceb1SPhilipp Tomsich 	struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
455cf8aceb1SPhilipp Tomsich 	ulong rate = 0;
456cf8aceb1SPhilipp Tomsich 
457cf8aceb1SPhilipp Tomsich 	debug("%s: id %ld\n", __func__, clk->id);
458cf8aceb1SPhilipp Tomsich 	switch (clk->id) {
459cf8aceb1SPhilipp Tomsich 	case PLL_CPLL:
460cf8aceb1SPhilipp Tomsich 		rate = rkclk_pll_get_rate(priv->cru, CPLL);
461cf8aceb1SPhilipp Tomsich 		break;
462cf8aceb1SPhilipp Tomsich 	case PLL_GPLL:
463cf8aceb1SPhilipp Tomsich 		rate = rkclk_pll_get_rate(priv->cru, GPLL);
464cf8aceb1SPhilipp Tomsich 		break;
465cf8aceb1SPhilipp Tomsich 	case SCLK_SPI0 ... SCLK_SPI2:
466cf8aceb1SPhilipp Tomsich 		rate = rk3368_spi_get_clk(priv->cru, clk->id);
467cf8aceb1SPhilipp Tomsich 		break;
468cf8aceb1SPhilipp Tomsich #if !IS_ENABLED(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(MMC_SUPPORT)
469cf8aceb1SPhilipp Tomsich 	case HCLK_SDMMC:
470cf8aceb1SPhilipp Tomsich 	case HCLK_EMMC:
471cf8aceb1SPhilipp Tomsich 		rate = rk3368_mmc_get_clk(priv->cru, clk->id);
472cf8aceb1SPhilipp Tomsich 		break;
473cf8aceb1SPhilipp Tomsich #endif
474615514c1SDavid Wu 	case SCLK_SARADC:
475615514c1SDavid Wu 		rate = rk3368_saradc_get_clk(priv->cru);
476615514c1SDavid Wu 		break;
477cf8aceb1SPhilipp Tomsich 	default:
478cf8aceb1SPhilipp Tomsich 		return -ENOENT;
479cf8aceb1SPhilipp Tomsich 	}
480cf8aceb1SPhilipp Tomsich 
481cf8aceb1SPhilipp Tomsich 	return rate;
482cf8aceb1SPhilipp Tomsich }
483cf8aceb1SPhilipp Tomsich 
rk3368_clk_set_rate(struct clk * clk,ulong rate)484d1dcf852SAndy Yan static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate)
485d1dcf852SAndy Yan {
4864e4c40dfSPhilipp Tomsich 	__maybe_unused struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
487d1dcf852SAndy Yan 	ulong ret = 0;
488d1dcf852SAndy Yan 
489d1dcf852SAndy Yan 	debug("%s id:%ld rate:%ld\n", __func__, clk->id, rate);
490d1dcf852SAndy Yan 	switch (clk->id) {
491cf8aceb1SPhilipp Tomsich 	case SCLK_SPI0 ... SCLK_SPI2:
492cf8aceb1SPhilipp Tomsich 		ret = rk3368_spi_set_clk(priv->cru, clk->id, rate);
493cf8aceb1SPhilipp Tomsich 		break;
49462924690SPhilipp Tomsich #if IS_ENABLED(CONFIG_TPL_BUILD)
495a00dfa04SPhilipp Tomsich 	case CLK_DDR:
496a00dfa04SPhilipp Tomsich 		ret = rk3368_ddr_set_clk(priv->cru, rate);
497a00dfa04SPhilipp Tomsich 		break;
49862924690SPhilipp Tomsich #endif
499f5a43295SPhilipp Tomsich #if !IS_ENABLED(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(MMC_SUPPORT)
500f5a43295SPhilipp Tomsich 	case HCLK_SDMMC:
501f5a43295SPhilipp Tomsich 	case HCLK_EMMC:
502f5a43295SPhilipp Tomsich 		ret = rk3368_mmc_set_clk(clk, rate);
503f5a43295SPhilipp Tomsich 		break;
504f5a43295SPhilipp Tomsich #endif
505df0ae000SPhilipp Tomsich #if CONFIG_IS_ENABLED(GMAC_ROCKCHIP)
506f5a43295SPhilipp Tomsich 	case SCLK_MAC:
507df0ae000SPhilipp Tomsich 		/* select the external clock */
50864a12202SDavid Wu 		ret = rk3368_gmac_set_clk(priv->cru, rate);
509d1dcf852SAndy Yan 		break;
510df0ae000SPhilipp Tomsich #endif
511615514c1SDavid Wu 	case SCLK_SARADC:
512615514c1SDavid Wu 		ret =  rk3368_saradc_set_clk(priv->cru, rate);
513615514c1SDavid Wu 		break;
514d1dcf852SAndy Yan 	default:
515d1dcf852SAndy Yan 		return -ENOENT;
516d1dcf852SAndy Yan 	}
517d1dcf852SAndy Yan 
518d1dcf852SAndy Yan 	return ret;
519d1dcf852SAndy Yan }
520d1dcf852SAndy Yan 
rk3368_gmac_set_parent(struct clk * clk,struct clk * parent)52175b381aaSPhilipp Tomsich static int __maybe_unused rk3368_gmac_set_parent(struct clk *clk, struct clk *parent)
52264a12202SDavid Wu {
52364a12202SDavid Wu 	struct rk3368_clk_priv *priv = dev_get_priv(clk->dev);
52464a12202SDavid Wu 	struct rk3368_cru *cru = priv->cru;
52564a12202SDavid Wu 	const char *clock_output_name;
52664a12202SDavid Wu 	int ret;
52764a12202SDavid Wu 
52864a12202SDavid Wu 	/*
52964a12202SDavid Wu 	 * If the requested parent is in the same clock-controller and
53064a12202SDavid Wu 	 * the id is SCLK_MAC ("sclk_mac"), switch to the internal
53164a12202SDavid Wu 	 * clock.
53264a12202SDavid Wu 	 */
53364a12202SDavid Wu 	if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC)) {
53464a12202SDavid Wu 		debug("%s: switching GAMC to SCLK_MAC\n", __func__);
53564a12202SDavid Wu 		rk_clrreg(&cru->clksel_con[43], GMAC_MUX_SEL_EXTCLK);
53664a12202SDavid Wu 		return 0;
53764a12202SDavid Wu 	}
53864a12202SDavid Wu 
53964a12202SDavid Wu 	/*
54064a12202SDavid Wu 	 * Otherwise, we need to check the clock-output-names of the
54164a12202SDavid Wu 	 * requested parent to see if the requested id is "ext_gmac".
54264a12202SDavid Wu 	 */
54364a12202SDavid Wu 	ret = dev_read_string_index(parent->dev, "clock-output-names",
54464a12202SDavid Wu 				    parent->id, &clock_output_name);
54564a12202SDavid Wu 	if (ret < 0)
54664a12202SDavid Wu 		return -ENODATA;
54764a12202SDavid Wu 
54864a12202SDavid Wu 	/* If this is "ext_gmac", switch to the external clock input */
54964a12202SDavid Wu 	if (!strcmp(clock_output_name, "ext_gmac")) {
55064a12202SDavid Wu 		debug("%s: switching GMAC to external clock\n", __func__);
55164a12202SDavid Wu 		rk_setreg(&cru->clksel_con[43], GMAC_MUX_SEL_EXTCLK);
55264a12202SDavid Wu 		return 0;
55364a12202SDavid Wu 	}
55464a12202SDavid Wu 
55564a12202SDavid Wu 	return -EINVAL;
55664a12202SDavid Wu }
55764a12202SDavid Wu 
rk3368_clk_set_parent(struct clk * clk,struct clk * parent)55875b381aaSPhilipp Tomsich static int __maybe_unused rk3368_clk_set_parent(struct clk *clk, struct clk *parent)
55964a12202SDavid Wu {
56064a12202SDavid Wu 	switch (clk->id) {
56164a12202SDavid Wu 	case SCLK_MAC:
56264a12202SDavid Wu 		return rk3368_gmac_set_parent(clk, parent);
56364a12202SDavid Wu 	}
56464a12202SDavid Wu 
56564a12202SDavid Wu 	debug("%s: unsupported clk %ld\n", __func__, clk->id);
56664a12202SDavid Wu 	return -ENOENT;
56764a12202SDavid Wu }
56864a12202SDavid Wu 
rk3368_clk_enable(struct clk * clk)56935a69a3bSPhilipp Tomsich static int rk3368_clk_enable(struct clk *clk)
57035a69a3bSPhilipp Tomsich {
57135a69a3bSPhilipp Tomsich 	switch (clk->id) {
57235a69a3bSPhilipp Tomsich 	case SCLK_MAC:
57335a69a3bSPhilipp Tomsich 	case SCLK_MAC_RX:
57435a69a3bSPhilipp Tomsich 	case SCLK_MAC_TX:
57535a69a3bSPhilipp Tomsich 	case SCLK_MACREF:
57635a69a3bSPhilipp Tomsich 	case SCLK_MACREF_OUT:
57735a69a3bSPhilipp Tomsich 	case ACLK_GMAC:
57835a69a3bSPhilipp Tomsich 	case PCLK_GMAC:
57935a69a3bSPhilipp Tomsich 		/* Required to successfully probe the Designware GMAC driver */
58035a69a3bSPhilipp Tomsich 		return 0;
58135a69a3bSPhilipp Tomsich 	}
58235a69a3bSPhilipp Tomsich 
58335a69a3bSPhilipp Tomsich 	debug("%s: unsupported clk %ld\n", __func__, clk->id);
58435a69a3bSPhilipp Tomsich 	return -ENOENT;
58535a69a3bSPhilipp Tomsich }
58635a69a3bSPhilipp Tomsich 
587d1dcf852SAndy Yan static struct clk_ops rk3368_clk_ops = {
588d1dcf852SAndy Yan 	.get_rate = rk3368_clk_get_rate,
589d1dcf852SAndy Yan 	.set_rate = rk3368_clk_set_rate,
59075b381aaSPhilipp Tomsich #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
59164a12202SDavid Wu 	.set_parent = rk3368_clk_set_parent,
59275b381aaSPhilipp Tomsich #endif
59335a69a3bSPhilipp Tomsich 	.enable = rk3368_clk_enable,
594d1dcf852SAndy Yan };
595d1dcf852SAndy Yan 
rk3368_clk_probe(struct udevice * dev)596d1dcf852SAndy Yan static int rk3368_clk_probe(struct udevice *dev)
597d1dcf852SAndy Yan {
5984bebf94eSPhilipp Tomsich 	struct rk3368_clk_priv __maybe_unused *priv = dev_get_priv(dev);
599bee61801SPhilipp Tomsich #if CONFIG_IS_ENABLED(OF_PLATDATA)
600bee61801SPhilipp Tomsich 	struct rk3368_clk_plat *plat = dev_get_platdata(dev);
601d1dcf852SAndy Yan 
602c20ee0edSSimon Glass 	priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
603bee61801SPhilipp Tomsich #endif
6044bebf94eSPhilipp Tomsich #if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD)
605d1dcf852SAndy Yan 	rkclk_init(priv->cru);
6064bebf94eSPhilipp Tomsich #endif
607d1dcf852SAndy Yan 
608d1dcf852SAndy Yan 	return 0;
609d1dcf852SAndy Yan }
610d1dcf852SAndy Yan 
rk3368_clk_ofdata_to_platdata(struct udevice * dev)611d1dcf852SAndy Yan static int rk3368_clk_ofdata_to_platdata(struct udevice *dev)
612d1dcf852SAndy Yan {
613bee61801SPhilipp Tomsich #if !CONFIG_IS_ENABLED(OF_PLATDATA)
614d1dcf852SAndy Yan 	struct rk3368_clk_priv *priv = dev_get_priv(dev);
615d1dcf852SAndy Yan 
6169a342f48SPhilipp Tomsich 	priv->cru = dev_read_addr_ptr(dev);
617bee61801SPhilipp Tomsich #endif
618d1dcf852SAndy Yan 
619d1dcf852SAndy Yan 	return 0;
620d1dcf852SAndy Yan }
621d1dcf852SAndy Yan 
rk3368_clk_bind(struct udevice * dev)622d1dcf852SAndy Yan static int rk3368_clk_bind(struct udevice *dev)
623d1dcf852SAndy Yan {
624d1dcf852SAndy Yan 	int ret;
625f24e36daSKever Yang 	struct udevice *sys_child;
626f24e36daSKever Yang 	struct sysreset_reg *priv;
627d1dcf852SAndy Yan 
628d1dcf852SAndy Yan 	/* The reset driver does not have a device node, so bind it here */
629f24e36daSKever Yang 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
630f24e36daSKever Yang 				 &sys_child);
631f24e36daSKever Yang 	if (ret) {
632f24e36daSKever Yang 		debug("Warning: No sysreset driver: ret=%d\n", ret);
633f24e36daSKever Yang 	} else {
634f24e36daSKever Yang 		priv = malloc(sizeof(struct sysreset_reg));
635f24e36daSKever Yang 		priv->glb_srst_fst_value = offsetof(struct rk3368_cru,
636f24e36daSKever Yang 						    glb_srst_fst_val);
637f24e36daSKever Yang 		priv->glb_srst_snd_value = offsetof(struct rk3368_cru,
638f24e36daSKever Yang 						    glb_srst_snd_val);
639f24e36daSKever Yang 		sys_child->priv = priv;
640f24e36daSKever Yang 	}
641d1dcf852SAndy Yan 
642538f67c3SElaine Zhang #if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
643538f67c3SElaine Zhang 	ret = offsetof(struct rk3368_cru, softrst_con[0]);
644538f67c3SElaine Zhang 	ret = rockchip_reset_bind(dev, ret, 15);
645538f67c3SElaine Zhang 	if (ret)
646538f67c3SElaine Zhang 		debug("Warning: software reset driver bind faile\n");
647538f67c3SElaine Zhang #endif
648538f67c3SElaine Zhang 
649d1dcf852SAndy Yan 	return ret;
650d1dcf852SAndy Yan }
651d1dcf852SAndy Yan 
652d1dcf852SAndy Yan static const struct udevice_id rk3368_clk_ids[] = {
653d1dcf852SAndy Yan 	{ .compatible = "rockchip,rk3368-cru" },
654d1dcf852SAndy Yan 	{ }
655d1dcf852SAndy Yan };
656d1dcf852SAndy Yan 
657d1dcf852SAndy Yan U_BOOT_DRIVER(rockchip_rk3368_cru) = {
658d1dcf852SAndy Yan 	.name		= "rockchip_rk3368_cru",
659d1dcf852SAndy Yan 	.id		= UCLASS_CLK,
660d1dcf852SAndy Yan 	.of_match	= rk3368_clk_ids,
661cdc6080aSPhilipp Tomsich 	.priv_auto_alloc_size = sizeof(struct rk3368_clk_priv),
662bee61801SPhilipp Tomsich #if CONFIG_IS_ENABLED(OF_PLATDATA)
663bee61801SPhilipp Tomsich 	.platdata_auto_alloc_size = sizeof(struct rk3368_clk_plat),
664bee61801SPhilipp Tomsich #endif
665d1dcf852SAndy Yan 	.ofdata_to_platdata = rk3368_clk_ofdata_to_platdata,
666d1dcf852SAndy Yan 	.ops		= &rk3368_clk_ops,
667d1dcf852SAndy Yan 	.bind		= rk3368_clk_bind,
668d1dcf852SAndy Yan 	.probe		= rk3368_clk_probe,
669d1dcf852SAndy Yan };
670