xref: /openbmc/u-boot/drivers/clk/aspeed/clk_ast2500.c (revision afbe1ac3aa318e100b420971ac7957fcc35710c7)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) Copyright 2016 Google, Inc
4  *
5  * Copyright (C) ASPEED Technology Inc.
6  *
7  */
8 
9 #include <common.h>
10 #include <clk-uclass.h>
11 #include <dm.h>
12 #include <asm/io.h>
13 #include <dm/lists.h>
14 #include <asm/arch/scu_ast2500.h>
15 #include <dt-bindings/clock/ast2500-clock.h>
16 #include <dt-bindings/reset/ast2500-reset.h>
17 
18 /*
19  * MAC Clock Delay settings, taken from Aspeed SDK
20  */
21 #define RGMII_TXCLK_ODLY		8
22 #define RMII_RXCLK_IDLY		2
23 
24 /*
25  * TGMII Clock Duty constants, taken from Aspeed SDK
26  */
27 #define RGMII2_TXCK_DUTY	0x66
28 #define RGMII1_TXCK_DUTY	0x64
29 
30 #define D2PLL_DEFAULT_RATE	(250 * 1000 * 1000)
31 
32 DECLARE_GLOBAL_DATA_PTR;
33 
34 /*
35  * Clock divider/multiplier configuration struct.
36  * For H-PLL and M-PLL the formula is
37  * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1)
38  * M - Numerator
39  * N - Denumerator
40  * P - Post Divider
41  * They have the same layout in their control register.
42  *
43  * D-PLL and D2-PLL have extra divider (OD + 1), which is not
44  * yet needed and ignored by clock configurations.
45  */
46 struct ast2500_div_config {
47 	unsigned int num;
48 	unsigned int denum;
49 	unsigned int post_div;
50 };
51 
52 extern u32 ast2500_get_clkin(struct ast2500_scu *scu)
53 {
54 	return readl(&scu->hwstrap) & SCU_HWSTRAP_CLKIN_25MHZ
55 			? 25 * 1000 * 1000 : 24 * 1000 * 1000;
56 }
57 
58 /*
59  * Get the rate of the M-PLL clock from input clock frequency and
60  * the value of the M-PLL Parameter Register.
61  */
62 extern u32 ast2500_get_mpll_rate(struct ast2500_scu *scu)
63 {
64 	u32 clkin = ast2500_get_clkin(scu);
65 	u32 mpll_reg = readl(&scu->m_pll_param);
66 
67 	const ulong num = (mpll_reg & SCU_MPLL_NUM_MASK) >> SCU_MPLL_NUM_SHIFT;
68 	const ulong denum = (mpll_reg & SCU_MPLL_DENUM_MASK)
69 			>> SCU_MPLL_DENUM_SHIFT;
70 	const ulong post_div = (mpll_reg & SCU_MPLL_POST_MASK)
71 			>> SCU_MPLL_POST_SHIFT;
72 
73 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
74 }
75 
76 /*
77  * Get the rate of the H-PLL clock from input clock frequency and
78  * the value of the H-PLL Parameter Register.
79  */
80 extern u32 ast2500_get_hpll_rate(struct ast2500_scu *scu)
81 {
82 	u32 clkin = ast2500_get_clkin(scu);
83 	u32 hpll_reg = readl(&scu->h_pll_param);
84 
85 	/* F = clkin * [(M+1) / (N+1)] / (P + 1) */
86 	const ulong num = (hpll_reg & SCU_HPLL_NUM_MASK) >> SCU_HPLL_NUM_SHIFT;
87 	const ulong denum = (hpll_reg & SCU_HPLL_DENUM_MASK)
88 			>> SCU_HPLL_DENUM_SHIFT;
89 	const ulong post_div = (hpll_reg & SCU_HPLL_POST_MASK)
90 			>> SCU_HPLL_POST_SHIFT;
91 
92 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
93 }
94 
95 /*
96  * Get the rate of the D-PLL clock from input clock frequency and
97  * the value of the D-PLL Parameter Register.
98  */
99 extern u32 ast2500_get_dpll_rate(struct ast2500_scu *scu)
100 {
101 	u32 clkin = ast2500_get_clkin(scu);
102 	u32 dpll_reg = readl(&scu->d_pll_param);
103 
104 	/* F = clkin * [(M+1) / (N+1)] / (P + 1)/ (od + 1) */
105 	const ulong num = (dpll_reg & 0xff);
106 	const ulong denum = (dpll_reg >> 8) & 0x1f;
107 	const ulong post_div = (dpll_reg >> 13) & 0x3f;
108 	const ulong od_div = (dpll_reg >> 19) & 0x7;
109 	return (((clkin * ((num + 1) / (denum + 1))) / (post_div + 1))/ (od_div + 1));
110 }
111 
112 /*
113  * Get the rate of the D2-PLL clock from input clock frequency and
114  * the value of the D2-PLL Parameter Register.
115  */
116 extern u32 ast2500_get_d2pll_rate(struct ast2500_scu *scu)
117 {
118 	u32 clkin = ast2500_get_clkin(scu);
119 	u32 d2pll_reg = readl(&scu->d2_pll_param);
120 
121 	/* F = clkin * [(M+1) / (N+1)] / (P + 1)/ (od + 1) */
122 	const ulong num = (d2pll_reg & 0xff);
123 	const ulong denum = (d2pll_reg >> 8) & 0x1f;
124 	const ulong post_div = (d2pll_reg >> 13) & 0x3f;
125 	const ulong od_div = (d2pll_reg >> 19) & 0x7 ;
126 
127 	return (((clkin * ((num + 1) / (denum + 1))) / (post_div + 1))/ (od_div + 1));
128 }
129 
130 #define SCU_HWSTRAP_AXIAHB_DIV_SHIFT    9
131 #define SCU_HWSTRAP_AXIAHB_DIV_MASK     (0x7 << SCU_HWSTRAP_AXIAHB_DIV_SHIFT)
132 
133 static u32 ast2500_get_hclk(struct ast2500_scu *scu)
134 {
135 	ulong ahb_div = 1 + ((readl(&scu->hwstrap)
136 			      & SCU_HWSTRAP_AXIAHB_DIV_MASK)
137 			     >> SCU_HWSTRAP_AXIAHB_DIV_SHIFT);
138 
139 	ulong axi_div = 2;
140 	u32 rate = 0;
141 
142 	rate = ast2500_get_hpll_rate(scu);
143 	return (rate / axi_div / ahb_div);
144 }
145 
146 static u32 ast2500_get_pclk(struct ast2500_scu *scu)
147 {
148 	u32 rate = 0;
149 	ulong apb_div = 4 + 4 * ((readl(&scu->clk_sel1)
150 				  & SCU_PCLK_DIV_MASK)
151 				 >> SCU_PCLK_DIV_SHIFT);
152 	rate = ast2500_get_hpll_rate(scu);
153 
154 	return (rate / apb_div);
155 }
156 
157 static u32 ast2500_get_sdio_clk_rate(struct ast2500_scu *scu)
158 {
159 	u32 clkin = ast2500_get_hpll_rate(scu);
160 	u32 clk_sel = readl(&scu->clk_sel1);
161 	u32 div = (clk_sel >> 12) & 0x7;
162 
163 	div = (div + 1) << 2;
164 
165 	return (clkin / div);
166 }
167 
168 static u32 ast2500_get_uart_clk_rate(struct ast2500_scu *scu, int uart_index)
169 {
170 	/*
171 	 * ast2500 datasheet is very confusing when it comes to UART clocks,
172 	 * especially when CLKIN = 25 MHz. The settings are in
173 	 * different registers and it is unclear how they interact.
174 	 *
175 	 * This has only been tested with default settings and CLKIN = 24 MHz.
176 	 */
177 	u32 uart_clkin;
178 
179 	if (readl(&scu->misc_ctrl2) &
180 	    (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT)))
181 		uart_clkin = 192 * 1000 * 1000;
182 	else
183 		uart_clkin = 24 * 1000 * 1000;
184 
185 	if (readl(&scu->misc_ctrl1) & SCU_MISC_UARTCLK_DIV13)
186 		uart_clkin /= 13;
187 
188 	return uart_clkin;
189 }
190 
191 static ulong ast2500_clk_get_rate(struct clk *clk)
192 {
193 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
194 	ulong rate;
195 
196 	switch (clk->id) {
197 	case ASPEED_CLK_HPLL:
198 		rate = ast2500_get_hpll_rate(priv->scu);
199 		break;
200 	case ASPEED_CLK_MPLL:
201 		rate = ast2500_get_mpll_rate(priv->scu);
202 		break;
203 	case ASPEED_CLK_AHB:
204 		rate = ast2500_get_hclk(priv->scu);
205 		break;
206 	case ASPEED_CLK_APB:
207 		rate = ast2500_get_pclk(priv->scu);
208 		break;
209 	case ASPEED_CLK_GATE_UART1CLK:
210 		rate = ast2500_get_uart_clk_rate(priv->scu, 1);
211 		break;
212 	case ASPEED_CLK_GATE_UART2CLK:
213 		rate = ast2500_get_uart_clk_rate(priv->scu, 2);
214 		break;
215 	case ASPEED_CLK_GATE_UART3CLK:
216 		rate = ast2500_get_uart_clk_rate(priv->scu, 3);
217 		break;
218 	case ASPEED_CLK_GATE_UART4CLK:
219 		rate = ast2500_get_uart_clk_rate(priv->scu, 4);
220 		break;
221 	case ASPEED_CLK_GATE_UART5CLK:
222 		rate = ast2500_get_uart_clk_rate(priv->scu, 5);
223 		break;
224 	case ASPEED_CLK_SDIO:
225 		rate = ast2500_get_sdio_clk_rate(priv->scu);
226 		break;
227 	default:
228 		pr_debug("can't get clk rate \n");
229 		return -ENOENT;
230 		break;
231 	}
232 
233 	return rate;
234 }
235 
236 struct ast2500_clock_config {
237 	ulong input_rate;
238 	ulong rate;
239 	struct ast2500_div_config cfg;
240 };
241 
242 static const struct ast2500_clock_config ast2500_clock_config_defaults[] = {
243 	{ 24000000, 250000000, { .num = 124, .denum = 1, .post_div = 5 } },
244 };
245 
246 static bool ast2500_get_clock_config_default(ulong input_rate,
247 					     ulong requested_rate,
248 					     struct ast2500_div_config *cfg)
249 {
250 	int i;
251 
252 	for (i = 0; i < ARRAY_SIZE(ast2500_clock_config_defaults); i++) {
253 		const struct ast2500_clock_config *default_cfg =
254 			&ast2500_clock_config_defaults[i];
255 		if (default_cfg->input_rate == input_rate &&
256 		    default_cfg->rate == requested_rate) {
257 			*cfg = default_cfg->cfg;
258 			return true;
259 		}
260 	}
261 
262 	return false;
263 }
264 
265 /*
266  * @input_rate - the rate of input clock in Hz
267  * @requested_rate - desired output rate in Hz
268  * @div - this is an IN/OUT parameter, at input all fields of the config
269  * need to be set to their maximum allowed values.
270  * The result (the best config we could find), would also be returned
271  * in this structure.
272  *
273  * @return The clock rate, when the resulting div_config is used.
274  */
275 static ulong ast2500_calc_clock_config(ulong input_rate, ulong requested_rate,
276 				       struct ast2500_div_config *cfg)
277 {
278 	/*
279 	 * The assumption is that kHz precision is good enough and
280 	 * also enough to avoid overflow when multiplying.
281 	 */
282 	const ulong input_rate_khz = input_rate / 1000;
283 	const ulong rate_khz = requested_rate / 1000;
284 	const struct ast2500_div_config max_vals = *cfg;
285 	struct ast2500_div_config it = { 0, 0, 0 };
286 	ulong delta = rate_khz;
287 	ulong new_rate_khz = 0;
288 
289 	/*
290 	 * Look for a well known frequency first.
291 	 */
292 	if (ast2500_get_clock_config_default(input_rate, requested_rate, cfg))
293 		return requested_rate;
294 
295 	for (; it.denum <= max_vals.denum; ++it.denum) {
296 		for (it.post_div = 0; it.post_div <= max_vals.post_div;
297 		     ++it.post_div) {
298 			it.num = (rate_khz * (it.post_div + 1) / input_rate_khz)
299 			    * (it.denum + 1);
300 			if (it.num > max_vals.num)
301 				continue;
302 
303 			new_rate_khz = (input_rate_khz
304 					* ((it.num + 1) / (it.denum + 1)))
305 			    / (it.post_div + 1);
306 
307 			/* Keep the rate below requested one. */
308 			if (new_rate_khz > rate_khz)
309 				continue;
310 
311 			if (new_rate_khz - rate_khz < delta) {
312 				delta = new_rate_khz - rate_khz;
313 				*cfg = it;
314 				if (delta == 0)
315 					return new_rate_khz * 1000;
316 			}
317 		}
318 	}
319 
320 	return new_rate_khz * 1000;
321 }
322 
323 static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate)
324 {
325 	ulong clkin = ast2500_get_clkin(scu);
326 	u32 mpll_reg;
327 	struct ast2500_div_config div_cfg = {
328 		.num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT),
329 		.denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT),
330 		.post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT),
331 	};
332 
333 	ast2500_calc_clock_config(clkin, rate, &div_cfg);
334 
335 	mpll_reg = readl(&scu->m_pll_param);
336 	mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK
337 		      | SCU_MPLL_DENUM_MASK);
338 	mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT)
339 	    | (div_cfg.num << SCU_MPLL_NUM_SHIFT)
340 	    | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT);
341 
342 	writel(mpll_reg, &scu->m_pll_param);
343 
344 	return ast2500_get_mpll_rate(scu);
345 }
346 
347 static ulong ast2500_configure_d2pll(struct ast2500_scu *scu, ulong rate)
348 {
349 	/*
350 	 * The values and the meaning of the next three
351 	 * parameters are undocumented. Taken from Aspeed SDK.
352 	 *
353 	 * TODO(clg@kaod.org): the SIP and SIC values depend on the
354 	 * Numerator value
355 	 */
356 	const u32 d2_pll_ext_param = 0x2c;
357 	const u32 d2_pll_sip = 0x11;
358 	const u32 d2_pll_sic = 0x18;
359 	struct ast2500_div_config div_cfg = {
360 		.num = SCU_D2PLL_NUM_MASK >> SCU_D2PLL_NUM_SHIFT,
361 		.denum = SCU_D2PLL_DENUM_MASK >> SCU_D2PLL_DENUM_SHIFT,
362 		.post_div = SCU_D2PLL_POST_MASK >> SCU_D2PLL_POST_SHIFT,
363 	};
364 	ulong clkin = ast2500_get_clkin(scu);
365 	ulong new_rate;
366 
367 	writel((d2_pll_ext_param << SCU_D2PLL_EXT1_PARAM_SHIFT)
368 	       | SCU_D2PLL_EXT1_OFF
369 	       | SCU_D2PLL_EXT1_RESET, &scu->d2_pll_ext_param[0]);
370 
371 	/*
372 	 * Select USB2.0 port1 PHY clock as a clock source for GCRT.
373 	 * This would disconnect it from D2-PLL.
374 	 */
375 	clrsetbits_le32(&scu->misc_ctrl1, SCU_MISC_D2PLL_OFF,
376 			SCU_MISC_GCRT_USB20CLK);
377 
378 	new_rate = ast2500_calc_clock_config(clkin, rate, &div_cfg);
379 	writel((d2_pll_sip << SCU_D2PLL_SIP_SHIFT)
380 	       | (d2_pll_sic << SCU_D2PLL_SIC_SHIFT)
381 	       | (div_cfg.num << SCU_D2PLL_NUM_SHIFT)
382 	       | (div_cfg.denum << SCU_D2PLL_DENUM_SHIFT)
383 	       | (div_cfg.post_div << SCU_D2PLL_POST_SHIFT),
384 	       &scu->d2_pll_param);
385 
386 	clrbits_le32(&scu->d2_pll_ext_param[0],
387 		     SCU_D2PLL_EXT1_OFF | SCU_D2PLL_EXT1_RESET);
388 
389 	clrsetbits_le32(&scu->misc_ctrl2,
390 			SCU_MISC2_RGMII_HPLL | SCU_MISC2_RMII_MPLL
391 			| SCU_MISC2_RGMII_CLKDIV_MASK |
392 			SCU_MISC2_RMII_CLKDIV_MASK,
393 			(4 << SCU_MISC2_RMII_CLKDIV_SHIFT));
394 
395 	return new_rate;
396 }
397 
398 static unsigned long ast2500_clk_set_rate(struct clk *clk, ulong rate)
399 {
400 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
401 
402 	ulong new_rate;
403 	switch (clk->id) {
404 	//mpll
405 	case ASPEED_CLK_MPLL:
406 		new_rate = ast2500_configure_ddr(priv->scu, rate);
407 //		printf("ast2500_clk_set_rate mpll %ld \n", new_rate);
408 		break;
409 	case ASPEED_CLK_D2PLL:
410 		new_rate = ast2500_configure_d2pll(priv->scu, rate);
411 //		printf("ast2500_clk_set_rate d2pll ==== %ld \n", new_rate);
412 		break;
413 	default:
414 		return -ENOENT;
415 	}
416 
417 	return new_rate;
418 }
419 
420 #define SCU_CLKSTOP_MAC1		(20)
421 #define SCU_CLKSTOP_MAC2		(21)
422 
423 static ulong ast2500_configure_mac(struct ast2500_scu *scu, int index)
424 {
425 	ulong hpll_rate = ast2500_get_hpll_rate(scu);
426 	ulong required_rate;
427 	u32 hwstrap;
428 	u32 divisor;
429 	u32 reset_bit;
430 	u32 clkstop_bit;
431 	u32 clk_delay_settings =
432 		(RMII_RXCLK_IDLY << SCU_MICDS_MAC1RMII_RDLY_SHIFT)
433 		| (RMII_RXCLK_IDLY << SCU_MICDS_MAC2RMII_RDLY_SHIFT)
434 		| (RGMII_TXCLK_ODLY << SCU_MICDS_MAC1RGMII_TXDLY_SHIFT)
435 		| (RGMII_TXCLK_ODLY << SCU_MICDS_MAC2RGMII_TXDLY_SHIFT);
436 
437 	/*
438 	 * According to data sheet, for 10/100 mode the MAC clock frequency
439 	 * should be at least 25MHz and for 1000 mode at least 100MHz
440 	 */
441 	hwstrap = readl(&scu->hwstrap);
442 	if (hwstrap & (SCU_HWSTRAP_MAC1_RGMII | SCU_HWSTRAP_MAC2_RGMII))
443 		required_rate = 100 * 1000 * 1000;
444 	else
445 		required_rate = 25 * 1000 * 1000;
446 
447 	divisor = hpll_rate / required_rate;
448 
449 	if (divisor < 4) {
450 		/* Clock can't run fast enough, but let's try anyway */
451 		debug("MAC clock too slow\n");
452 		divisor = 4;
453 	} else if (divisor > 16) {
454 		/* Can't slow down the clock enough, but let's try anyway */
455 		debug("MAC clock too fast\n");
456 		divisor = 16;
457 	}
458 
459 	switch (index) {
460 	case 1:
461 		reset_bit = BIT(ASPEED_RESET_MAC1);
462 		clkstop_bit = BIT(SCU_CLKSTOP_MAC1);
463 		break;
464 	case 2:
465 		reset_bit = BIT(ASPEED_RESET_MAC2);
466 		clkstop_bit = BIT(SCU_CLKSTOP_MAC2);
467 		break;
468 	default:
469 		return -EINVAL;
470 	}
471 
472 	clrsetbits_le32(&scu->clk_sel1, SCU_MACCLK_MASK,
473 			((divisor - 2) / 2) << SCU_MACCLK_SHIFT);
474 
475 	/*
476 	 * Disable MAC, start its clock and re-enable it.
477 	 * The procedure and the delays (100us & 10ms) are
478 	 * specified in the datasheet.
479 	 */
480 	setbits_le32(&scu->sysreset_ctrl1, reset_bit);
481 	udelay(100);
482 	clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit);
483 	mdelay(10);
484 	clrbits_le32(&scu->sysreset_ctrl1, reset_bit);
485 
486 	writel((RGMII2_TXCK_DUTY << SCU_CLKDUTY_RGMII2TXCK_SHIFT)
487 	       | (RGMII1_TXCK_DUTY << SCU_CLKDUTY_RGMII1TXCK_SHIFT),
488 	       &scu->clk_duty_sel);
489 
490 	writel(clk_delay_settings | SCU_MICDS_RGMIIPLL, &scu->mac_clk_delay);
491 	writel(clk_delay_settings, &scu->mac_clk_delay_100M);
492 	writel(clk_delay_settings, &scu->mac_clk_delay_10M);
493 
494 	return required_rate;
495 }
496 
497 #define SCU_CLKSTOP_SDIO 27
498 static ulong ast2500_enable_sdclk(struct ast2500_scu *scu)
499 {
500 	u32 reset_bit;
501 	u32 clkstop_bit;
502 
503 	reset_bit = BIT(ASEPPD_RESET_SDIO);
504 	clkstop_bit = BIT(SCU_CLKSTOP_SDIO);
505 
506 	setbits_le32(&scu->sysreset_ctrl1, reset_bit);
507 	udelay(100);
508 	//enable clk
509 	clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit);
510 	mdelay(10);
511 	clrbits_le32(&scu->sysreset_ctrl1, reset_bit);
512 
513 	return 0;
514 }
515 
516 #define SCU_CLKSTOP_EXTSD 15
517 #define SCU_CLK_SD_MASK				(0x7 << 12)
518 #define SCU_CLK_SD_DIV(x)			(x << 12)
519 
520 static ulong ast2500_enable_extsdclk(struct ast2500_scu *scu)
521 {
522 	u32 clk_sel = readl(&scu->clk_sel1);
523 	u32 enableclk_bit;
524 
525 	enableclk_bit = BIT(SCU_CLKSTOP_EXTSD);
526 
527 	// SDCLK = G4  H-PLL / 4, G5 = H-PLL /8
528 	clk_sel &= ~SCU_CLK_SD_MASK;
529 	clk_sel |= SCU_CLK_SD_DIV(1);
530 	writel(clk_sel, &scu->clk_sel1);
531 
532 	//enable clk
533 	setbits_le32(&scu->clk_sel1, enableclk_bit);
534 
535 	return 0;
536 }
537 
538 static int ast2500_clk_enable(struct clk *clk)
539 {
540 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
541 
542 	switch (clk->id) {
543 	/*
544 	 * For MAC clocks the clock rate is
545 	 * configured based on whether RGMII or RMII mode has been selected
546 	 * through hardware strapping.
547 	 */
548 	case ASPEED_CLK_GATE_MAC1CLK:
549 		ast2500_configure_mac(priv->scu, 1);
550 		break;
551 	case ASPEED_CLK_GATE_MAC2CLK:
552 		ast2500_configure_mac(priv->scu, 2);
553 		break;
554 	case ASPEED_CLK_D2PLL:
555 		ast2500_configure_d2pll(priv->scu, D2PLL_DEFAULT_RATE);
556 		break;
557 	case ASPEED_CLK_GATE_SDCLK:
558 		ast2500_enable_sdclk(priv->scu);
559 		break;
560 	case ASPEED_CLK_GATE_SDEXTCLK:
561 		ast2500_enable_extsdclk(priv->scu);
562 		break;
563 	default:
564 		pr_debug("can't enable clk \n");
565 		return -ENOENT;
566 		break;
567 	}
568 
569 	return 0;
570 }
571 
572 struct clk_ops ast2500_clk_ops = {
573 	.get_rate = ast2500_clk_get_rate,
574 	.set_rate = ast2500_clk_set_rate,
575 	.enable = ast2500_clk_enable,
576 };
577 
578 static int ast2500_clk_probe(struct udevice *dev)
579 {
580 	struct ast2500_clk_priv *priv = dev_get_priv(dev);
581 
582 	priv->scu = devfdt_get_addr_ptr(dev);
583 	if (IS_ERR(priv->scu))
584 		return PTR_ERR(priv->scu);
585 
586 	return 0;
587 }
588 
589 static int ast2500_clk_bind(struct udevice *dev)
590 {
591 	int ret;
592 
593 	/* The reset driver does not have a device node, so bind it here */
594 	ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev);
595 	if (ret)
596 		debug("Warning: No reset driver: ret=%d\n", ret);
597 
598 	return 0;
599 }
600 
601 static const struct udevice_id ast2500_clk_ids[] = {
602 	{ .compatible = "aspeed,ast2500-scu" },
603 	{ }
604 };
605 
606 U_BOOT_DRIVER(aspeed_scu) = {
607 	.name		= "aspeed_scu",
608 	.id		= UCLASS_CLK,
609 	.of_match	= ast2500_clk_ids,
610 	.priv_auto_alloc_size = sizeof(struct ast2500_clk_priv),
611 	.ops		= &ast2500_clk_ops,
612 	.bind		= ast2500_clk_bind,
613 	.probe		= ast2500_clk_probe,
614 };
615