xref: /rk3399_rockchip-uboot/drivers/clk/aspeed/clk_ast2500.c (revision a821c4af79e4f5ce9b629b20473863397bbe9b10)
114e4b149Smaxims@google.com /*
214e4b149Smaxims@google.com  * (C) Copyright 2016 Google, Inc
314e4b149Smaxims@google.com  *
414e4b149Smaxims@google.com  * SPDX-License-Identifier:	GPL-2.0
514e4b149Smaxims@google.com  */
614e4b149Smaxims@google.com 
714e4b149Smaxims@google.com #include <common.h>
814e4b149Smaxims@google.com #include <clk-uclass.h>
914e4b149Smaxims@google.com #include <dm.h>
1014e4b149Smaxims@google.com #include <asm/io.h>
1114e4b149Smaxims@google.com #include <asm/arch/scu_ast2500.h>
1214e4b149Smaxims@google.com #include <dm/lists.h>
1314e4b149Smaxims@google.com #include <dt-bindings/clock/ast2500-scu.h>
1414e4b149Smaxims@google.com 
153b95902dSmaxims@google.com /*
163b95902dSmaxims@google.com  * MAC Clock Delay settings, taken from Aspeed SDK
173b95902dSmaxims@google.com  */
183b95902dSmaxims@google.com #define RGMII_TXCLK_ODLY		8
193b95902dSmaxims@google.com #define RMII_RXCLK_IDLY		2
203b95902dSmaxims@google.com 
213b95902dSmaxims@google.com /*
223b95902dSmaxims@google.com  * TGMII Clock Duty constants, taken from Aspeed SDK
233b95902dSmaxims@google.com  */
243b95902dSmaxims@google.com #define RGMII2_TXCK_DUTY	0x66
253b95902dSmaxims@google.com #define RGMII1_TXCK_DUTY	0x64
263b95902dSmaxims@google.com 
273b95902dSmaxims@google.com #define D2PLL_DEFAULT_RATE	(250 * 1000 * 1000)
283b95902dSmaxims@google.com 
2914e4b149Smaxims@google.com DECLARE_GLOBAL_DATA_PTR;
3014e4b149Smaxims@google.com 
3114e4b149Smaxims@google.com /*
323b95902dSmaxims@google.com  * Clock divider/multiplier configuration struct.
3314e4b149Smaxims@google.com  * For H-PLL and M-PLL the formula is
3414e4b149Smaxims@google.com  * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1)
3514e4b149Smaxims@google.com  * M - Numerator
3614e4b149Smaxims@google.com  * N - Denumerator
3714e4b149Smaxims@google.com  * P - Post Divider
3814e4b149Smaxims@google.com  * They have the same layout in their control register.
393b95902dSmaxims@google.com  *
403b95902dSmaxims@google.com  * D-PLL and D2-PLL have extra divider (OD + 1), which is not
413b95902dSmaxims@google.com  * yet needed and ignored by clock configurations.
4214e4b149Smaxims@google.com  */
433b95902dSmaxims@google.com struct ast2500_div_config {
443b95902dSmaxims@google.com 	unsigned int num;
453b95902dSmaxims@google.com 	unsigned int denum;
463b95902dSmaxims@google.com 	unsigned int post_div;
473b95902dSmaxims@google.com };
4814e4b149Smaxims@google.com 
4914e4b149Smaxims@google.com /*
5014e4b149Smaxims@google.com  * Get the rate of the M-PLL clock from input clock frequency and
5114e4b149Smaxims@google.com  * the value of the M-PLL Parameter Register.
5214e4b149Smaxims@google.com  */
ast2500_get_mpll_rate(ulong clkin,u32 mpll_reg)5314e4b149Smaxims@google.com static ulong ast2500_get_mpll_rate(ulong clkin, u32 mpll_reg)
5414e4b149Smaxims@google.com {
55defb1849Smaxims@google.com 	const ulong num = (mpll_reg & SCU_MPLL_NUM_MASK) >> SCU_MPLL_NUM_SHIFT;
56defb1849Smaxims@google.com 	const ulong denum = (mpll_reg & SCU_MPLL_DENUM_MASK)
57defb1849Smaxims@google.com 			>> SCU_MPLL_DENUM_SHIFT;
58defb1849Smaxims@google.com 	const ulong post_div = (mpll_reg & SCU_MPLL_POST_MASK)
59defb1849Smaxims@google.com 			>> SCU_MPLL_POST_SHIFT;
6014e4b149Smaxims@google.com 
61d5ce3574Smaxims@google.com 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
6214e4b149Smaxims@google.com }
6314e4b149Smaxims@google.com 
6414e4b149Smaxims@google.com /*
6514e4b149Smaxims@google.com  * Get the rate of the H-PLL clock from input clock frequency and
6614e4b149Smaxims@google.com  * the value of the H-PLL Parameter Register.
6714e4b149Smaxims@google.com  */
ast2500_get_hpll_rate(ulong clkin,u32 hpll_reg)6814e4b149Smaxims@google.com static ulong ast2500_get_hpll_rate(ulong clkin, u32 hpll_reg)
6914e4b149Smaxims@google.com {
70defb1849Smaxims@google.com 	const ulong num = (hpll_reg & SCU_HPLL_NUM_MASK) >> SCU_HPLL_NUM_SHIFT;
71defb1849Smaxims@google.com 	const ulong denum = (hpll_reg & SCU_HPLL_DENUM_MASK)
72defb1849Smaxims@google.com 			>> SCU_HPLL_DENUM_SHIFT;
73defb1849Smaxims@google.com 	const ulong post_div = (hpll_reg & SCU_HPLL_POST_MASK)
74defb1849Smaxims@google.com 			>> SCU_HPLL_POST_SHIFT;
7514e4b149Smaxims@google.com 
76d5ce3574Smaxims@google.com 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
7714e4b149Smaxims@google.com }
7814e4b149Smaxims@google.com 
ast2500_get_clkin(struct ast2500_scu * scu)7914e4b149Smaxims@google.com static ulong ast2500_get_clkin(struct ast2500_scu *scu)
8014e4b149Smaxims@google.com {
8114e4b149Smaxims@google.com 	return readl(&scu->hwstrap) & SCU_HWSTRAP_CLKIN_25MHZ
8214e4b149Smaxims@google.com 			? 25 * 1000 * 1000 : 24 * 1000 * 1000;
8314e4b149Smaxims@google.com }
8414e4b149Smaxims@google.com 
8514e4b149Smaxims@google.com /**
8614e4b149Smaxims@google.com  * Get current rate or uart clock
8714e4b149Smaxims@google.com  *
8814e4b149Smaxims@google.com  * @scu SCU registers
8914e4b149Smaxims@google.com  * @uart_index UART index, 1-5
9014e4b149Smaxims@google.com  *
9114e4b149Smaxims@google.com  * @return current setting for uart clock rate
9214e4b149Smaxims@google.com  */
ast2500_get_uart_clk_rate(struct ast2500_scu * scu,int uart_index)9314e4b149Smaxims@google.com static ulong ast2500_get_uart_clk_rate(struct ast2500_scu *scu, int uart_index)
9414e4b149Smaxims@google.com {
9514e4b149Smaxims@google.com 	/*
9614e4b149Smaxims@google.com 	 * ast2500 datasheet is very confusing when it comes to UART clocks,
9714e4b149Smaxims@google.com 	 * especially when CLKIN = 25 MHz. The settings are in
9814e4b149Smaxims@google.com 	 * different registers and it is unclear how they interact.
9914e4b149Smaxims@google.com 	 *
10014e4b149Smaxims@google.com 	 * This has only been tested with default settings and CLKIN = 24 MHz.
10114e4b149Smaxims@google.com 	 */
10214e4b149Smaxims@google.com 	ulong uart_clkin;
10314e4b149Smaxims@google.com 
10414e4b149Smaxims@google.com 	if (readl(&scu->misc_ctrl2) &
10514e4b149Smaxims@google.com 	    (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT)))
10614e4b149Smaxims@google.com 		uart_clkin = 192 * 1000 * 1000;
10714e4b149Smaxims@google.com 	else
10814e4b149Smaxims@google.com 		uart_clkin = 24 * 1000 * 1000;
10914e4b149Smaxims@google.com 
11014e4b149Smaxims@google.com 	if (readl(&scu->misc_ctrl1) & SCU_MISC_UARTCLK_DIV13)
11114e4b149Smaxims@google.com 		uart_clkin /= 13;
11214e4b149Smaxims@google.com 
11314e4b149Smaxims@google.com 	return uart_clkin;
11414e4b149Smaxims@google.com }
11514e4b149Smaxims@google.com 
ast2500_clk_get_rate(struct clk * clk)11614e4b149Smaxims@google.com static ulong ast2500_clk_get_rate(struct clk *clk)
11714e4b149Smaxims@google.com {
11814e4b149Smaxims@google.com 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
11914e4b149Smaxims@google.com 	ulong clkin = ast2500_get_clkin(priv->scu);
12014e4b149Smaxims@google.com 	ulong rate;
12114e4b149Smaxims@google.com 
12214e4b149Smaxims@google.com 	switch (clk->id) {
12314e4b149Smaxims@google.com 	case PLL_HPLL:
12414e4b149Smaxims@google.com 	case ARMCLK:
12514e4b149Smaxims@google.com 		/*
12614e4b149Smaxims@google.com 		 * This ignores dynamic/static slowdown of ARMCLK and may
12714e4b149Smaxims@google.com 		 * be inaccurate.
12814e4b149Smaxims@google.com 		 */
12914e4b149Smaxims@google.com 		rate = ast2500_get_hpll_rate(clkin,
13014e4b149Smaxims@google.com 					     readl(&priv->scu->h_pll_param));
13114e4b149Smaxims@google.com 		break;
13214e4b149Smaxims@google.com 	case MCLK_DDR:
13314e4b149Smaxims@google.com 		rate = ast2500_get_mpll_rate(clkin,
13414e4b149Smaxims@google.com 					     readl(&priv->scu->m_pll_param));
13514e4b149Smaxims@google.com 		break;
1364999bb06Smaxims@google.com 	case BCLK_PCLK:
1374999bb06Smaxims@google.com 		{
1384999bb06Smaxims@google.com 			ulong apb_div = 4 + 4 * ((readl(&priv->scu->clk_sel1)
139defb1849Smaxims@google.com 						  & SCU_PCLK_DIV_MASK)
140defb1849Smaxims@google.com 						 >> SCU_PCLK_DIV_SHIFT);
1414999bb06Smaxims@google.com 			rate = ast2500_get_hpll_rate(clkin,
142defb1849Smaxims@google.com 						     readl(&priv->
143defb1849Smaxims@google.com 							   scu->h_pll_param));
1444999bb06Smaxims@google.com 			rate = rate / apb_div;
1454999bb06Smaxims@google.com 		}
1464999bb06Smaxims@google.com 		break;
14714e4b149Smaxims@google.com 	case PCLK_UART1:
14814e4b149Smaxims@google.com 		rate = ast2500_get_uart_clk_rate(priv->scu, 1);
14914e4b149Smaxims@google.com 		break;
15014e4b149Smaxims@google.com 	case PCLK_UART2:
15114e4b149Smaxims@google.com 		rate = ast2500_get_uart_clk_rate(priv->scu, 2);
15214e4b149Smaxims@google.com 		break;
15314e4b149Smaxims@google.com 	case PCLK_UART3:
15414e4b149Smaxims@google.com 		rate = ast2500_get_uart_clk_rate(priv->scu, 3);
15514e4b149Smaxims@google.com 		break;
15614e4b149Smaxims@google.com 	case PCLK_UART4:
15714e4b149Smaxims@google.com 		rate = ast2500_get_uart_clk_rate(priv->scu, 4);
15814e4b149Smaxims@google.com 		break;
15914e4b149Smaxims@google.com 	case PCLK_UART5:
16014e4b149Smaxims@google.com 		rate = ast2500_get_uart_clk_rate(priv->scu, 5);
16114e4b149Smaxims@google.com 		break;
16214e4b149Smaxims@google.com 	default:
16314e4b149Smaxims@google.com 		return -ENOENT;
16414e4b149Smaxims@google.com 	}
16514e4b149Smaxims@google.com 
16614e4b149Smaxims@google.com 	return rate;
16714e4b149Smaxims@google.com }
16814e4b149Smaxims@google.com 
16914e4b149Smaxims@google.com /*
1703b95902dSmaxims@google.com  * @input_rate - the rate of input clock in Hz
1713b95902dSmaxims@google.com  * @requested_rate - desired output rate in Hz
1723b95902dSmaxims@google.com  * @div - this is an IN/OUT parameter, at input all fields of the config
1733b95902dSmaxims@google.com  * need to be set to their maximum allowed values.
1743b95902dSmaxims@google.com  * The result (the best config we could find), would also be returned
1753b95902dSmaxims@google.com  * in this structure.
1763b95902dSmaxims@google.com  *
1773b95902dSmaxims@google.com  * @return The clock rate, when the resulting div_config is used.
17814e4b149Smaxims@google.com  */
ast2500_calc_clock_config(ulong input_rate,ulong requested_rate,struct ast2500_div_config * cfg)1793b95902dSmaxims@google.com static ulong ast2500_calc_clock_config(ulong input_rate, ulong requested_rate,
1803b95902dSmaxims@google.com 				       struct ast2500_div_config *cfg)
1813b95902dSmaxims@google.com {
1823b95902dSmaxims@google.com 	/*
1833b95902dSmaxims@google.com 	 * The assumption is that kHz precision is good enough and
1843b95902dSmaxims@google.com 	 * also enough to avoid overflow when multiplying.
1853b95902dSmaxims@google.com 	 */
1863b95902dSmaxims@google.com 	const ulong input_rate_khz = input_rate / 1000;
1873b95902dSmaxims@google.com 	const ulong rate_khz = requested_rate / 1000;
1883b95902dSmaxims@google.com 	const struct ast2500_div_config max_vals = *cfg;
1893b95902dSmaxims@google.com 	struct ast2500_div_config it = { 0, 0, 0 };
1903b95902dSmaxims@google.com 	ulong delta = rate_khz;
1913b95902dSmaxims@google.com 	ulong new_rate_khz = 0;
19214e4b149Smaxims@google.com 
1933b95902dSmaxims@google.com 	for (; it.denum <= max_vals.denum; ++it.denum) {
1943b95902dSmaxims@google.com 		for (it.post_div = 0; it.post_div <= max_vals.post_div;
1953b95902dSmaxims@google.com 		     ++it.post_div) {
1963b95902dSmaxims@google.com 			it.num = (rate_khz * (it.post_div + 1) / input_rate_khz)
1973b95902dSmaxims@google.com 			    * (it.denum + 1);
1983b95902dSmaxims@google.com 			if (it.num > max_vals.num)
1993b95902dSmaxims@google.com 				continue;
2003b95902dSmaxims@google.com 
2013b95902dSmaxims@google.com 			new_rate_khz = (input_rate_khz
2023b95902dSmaxims@google.com 					* ((it.num + 1) / (it.denum + 1)))
2033b95902dSmaxims@google.com 			    / (it.post_div + 1);
20414e4b149Smaxims@google.com 
20514e4b149Smaxims@google.com 			/* Keep the rate below requested one. */
20614e4b149Smaxims@google.com 			if (new_rate_khz > rate_khz)
20714e4b149Smaxims@google.com 				continue;
20814e4b149Smaxims@google.com 
20914e4b149Smaxims@google.com 			if (new_rate_khz - rate_khz < delta) {
21014e4b149Smaxims@google.com 				delta = new_rate_khz - rate_khz;
2113b95902dSmaxims@google.com 				*cfg = it;
21214e4b149Smaxims@google.com 				if (delta == 0)
2133b95902dSmaxims@google.com 					return new_rate_khz * 1000;
21414e4b149Smaxims@google.com 			}
21514e4b149Smaxims@google.com 		}
21614e4b149Smaxims@google.com 	}
21714e4b149Smaxims@google.com 
2183b95902dSmaxims@google.com 	return new_rate_khz * 1000;
2193b95902dSmaxims@google.com }
2203b95902dSmaxims@google.com 
ast2500_configure_ddr(struct ast2500_scu * scu,ulong rate)2213b95902dSmaxims@google.com static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate)
2223b95902dSmaxims@google.com {
2233b95902dSmaxims@google.com 	ulong clkin = ast2500_get_clkin(scu);
2243b95902dSmaxims@google.com 	u32 mpll_reg;
2253b95902dSmaxims@google.com 	struct ast2500_div_config div_cfg = {
226defb1849Smaxims@google.com 		.num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT),
227defb1849Smaxims@google.com 		.denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT),
228defb1849Smaxims@google.com 		.post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT),
2293b95902dSmaxims@google.com 	};
2303b95902dSmaxims@google.com 
2313b95902dSmaxims@google.com 	ast2500_calc_clock_config(clkin, rate, &div_cfg);
2323b95902dSmaxims@google.com 
23314e4b149Smaxims@google.com 	mpll_reg = readl(&scu->m_pll_param);
234defb1849Smaxims@google.com 	mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK
235defb1849Smaxims@google.com 		      | SCU_MPLL_DENUM_MASK);
2363b95902dSmaxims@google.com 	mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT)
2373b95902dSmaxims@google.com 	    | (div_cfg.num << SCU_MPLL_NUM_SHIFT)
2383b95902dSmaxims@google.com 	    | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT);
23914e4b149Smaxims@google.com 
240413353b3Smaxims@google.com 	ast_scu_unlock(scu);
24114e4b149Smaxims@google.com 	writel(mpll_reg, &scu->m_pll_param);
242413353b3Smaxims@google.com 	ast_scu_lock(scu);
24314e4b149Smaxims@google.com 
24414e4b149Smaxims@google.com 	return ast2500_get_mpll_rate(clkin, mpll_reg);
24514e4b149Smaxims@google.com }
24614e4b149Smaxims@google.com 
ast2500_configure_mac(struct ast2500_scu * scu,int index)2473b95902dSmaxims@google.com static ulong ast2500_configure_mac(struct ast2500_scu *scu, int index)
2483b95902dSmaxims@google.com {
2493b95902dSmaxims@google.com 	ulong clkin = ast2500_get_clkin(scu);
2503b95902dSmaxims@google.com 	ulong hpll_rate = ast2500_get_hpll_rate(clkin,
2513b95902dSmaxims@google.com 						readl(&scu->h_pll_param));
2523b95902dSmaxims@google.com 	ulong required_rate;
2533b95902dSmaxims@google.com 	u32 hwstrap;
2543b95902dSmaxims@google.com 	u32 divisor;
2553b95902dSmaxims@google.com 	u32 reset_bit;
2563b95902dSmaxims@google.com 	u32 clkstop_bit;
2573b95902dSmaxims@google.com 
2583b95902dSmaxims@google.com 	/*
2593b95902dSmaxims@google.com 	 * According to data sheet, for 10/100 mode the MAC clock frequency
2603b95902dSmaxims@google.com 	 * should be at least 25MHz and for 1000 mode at least 100MHz
2613b95902dSmaxims@google.com 	 */
2623b95902dSmaxims@google.com 	hwstrap = readl(&scu->hwstrap);
2633b95902dSmaxims@google.com 	if (hwstrap & (SCU_HWSTRAP_MAC1_RGMII | SCU_HWSTRAP_MAC2_RGMII))
2643b95902dSmaxims@google.com 		required_rate = 100 * 1000 * 1000;
2653b95902dSmaxims@google.com 	else
2663b95902dSmaxims@google.com 		required_rate = 25 * 1000 * 1000;
2673b95902dSmaxims@google.com 
2683b95902dSmaxims@google.com 	divisor = hpll_rate / required_rate;
2693b95902dSmaxims@google.com 
2703b95902dSmaxims@google.com 	if (divisor < 4) {
2713b95902dSmaxims@google.com 		/* Clock can't run fast enough, but let's try anyway */
2723b95902dSmaxims@google.com 		debug("MAC clock too slow\n");
2733b95902dSmaxims@google.com 		divisor = 4;
2743b95902dSmaxims@google.com 	} else if (divisor > 16) {
2753b95902dSmaxims@google.com 		/* Can't slow down the clock enough, but let's try anyway */
2763b95902dSmaxims@google.com 		debug("MAC clock too fast\n");
2773b95902dSmaxims@google.com 		divisor = 16;
2783b95902dSmaxims@google.com 	}
2793b95902dSmaxims@google.com 
2803b95902dSmaxims@google.com 	switch (index) {
2813b95902dSmaxims@google.com 	case 1:
2823b95902dSmaxims@google.com 		reset_bit = SCU_SYSRESET_MAC1;
2833b95902dSmaxims@google.com 		clkstop_bit = SCU_CLKSTOP_MAC1;
2843b95902dSmaxims@google.com 		break;
2853b95902dSmaxims@google.com 	case 2:
2863b95902dSmaxims@google.com 		reset_bit = SCU_SYSRESET_MAC2;
2873b95902dSmaxims@google.com 		clkstop_bit = SCU_CLKSTOP_MAC2;
2883b95902dSmaxims@google.com 		break;
2893b95902dSmaxims@google.com 	default:
2903b95902dSmaxims@google.com 		return -EINVAL;
2913b95902dSmaxims@google.com 	}
2923b95902dSmaxims@google.com 
2933b95902dSmaxims@google.com 	ast_scu_unlock(scu);
2943b95902dSmaxims@google.com 	clrsetbits_le32(&scu->clk_sel1, SCU_MACCLK_MASK,
2953b95902dSmaxims@google.com 			((divisor - 2) / 2) << SCU_MACCLK_SHIFT);
2963b95902dSmaxims@google.com 
2973b95902dSmaxims@google.com 	/*
2983b95902dSmaxims@google.com 	 * Disable MAC, start its clock and re-enable it.
2993b95902dSmaxims@google.com 	 * The procedure and the delays (100us & 10ms) are
3003b95902dSmaxims@google.com 	 * specified in the datasheet.
3013b95902dSmaxims@google.com 	 */
3023b95902dSmaxims@google.com 	setbits_le32(&scu->sysreset_ctrl1, reset_bit);
3033b95902dSmaxims@google.com 	udelay(100);
3043b95902dSmaxims@google.com 	clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit);
3053b95902dSmaxims@google.com 	mdelay(10);
3063b95902dSmaxims@google.com 	clrbits_le32(&scu->sysreset_ctrl1, reset_bit);
3073b95902dSmaxims@google.com 
3083b95902dSmaxims@google.com 	writel((RGMII2_TXCK_DUTY << SCU_CLKDUTY_RGMII2TXCK_SHIFT)
3093b95902dSmaxims@google.com 	       | (RGMII1_TXCK_DUTY << SCU_CLKDUTY_RGMII1TXCK_SHIFT),
3103b95902dSmaxims@google.com 	       &scu->clk_duty_sel);
3113b95902dSmaxims@google.com 
3123b95902dSmaxims@google.com 	ast_scu_lock(scu);
3133b95902dSmaxims@google.com 
3143b95902dSmaxims@google.com 	return required_rate;
3153b95902dSmaxims@google.com }
3163b95902dSmaxims@google.com 
ast2500_configure_d2pll(struct ast2500_scu * scu,ulong rate)3173b95902dSmaxims@google.com static ulong ast2500_configure_d2pll(struct ast2500_scu *scu, ulong rate)
3183b95902dSmaxims@google.com {
3193b95902dSmaxims@google.com 	/*
3203b95902dSmaxims@google.com 	 * The values and the meaning of the next three
3213b95902dSmaxims@google.com 	 * parameters are undocumented. Taken from Aspeed SDK.
3223b95902dSmaxims@google.com 	 */
3233b95902dSmaxims@google.com 	const u32 d2_pll_ext_param = 0x2c;
3243b95902dSmaxims@google.com 	const u32 d2_pll_sip = 0x11;
3253b95902dSmaxims@google.com 	const u32 d2_pll_sic = 0x18;
3263b95902dSmaxims@google.com 	u32 clk_delay_settings =
3273b95902dSmaxims@google.com 	    (RMII_RXCLK_IDLY << SCU_MICDS_MAC1RMII_RDLY_SHIFT)
3283b95902dSmaxims@google.com 	    | (RMII_RXCLK_IDLY << SCU_MICDS_MAC2RMII_RDLY_SHIFT)
3293b95902dSmaxims@google.com 	    | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC1RGMII_TXDLY_SHIFT)
3303b95902dSmaxims@google.com 	    | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC2RGMII_TXDLY_SHIFT);
3313b95902dSmaxims@google.com 	struct ast2500_div_config div_cfg = {
3323b95902dSmaxims@google.com 		.num = SCU_D2PLL_NUM_MASK >> SCU_D2PLL_NUM_SHIFT,
3333b95902dSmaxims@google.com 		.denum = SCU_D2PLL_DENUM_MASK >> SCU_D2PLL_DENUM_SHIFT,
3343b95902dSmaxims@google.com 		.post_div = SCU_D2PLL_POST_MASK >> SCU_D2PLL_POST_SHIFT,
3353b95902dSmaxims@google.com 	};
3363b95902dSmaxims@google.com 	ulong clkin = ast2500_get_clkin(scu);
3373b95902dSmaxims@google.com 	ulong new_rate;
3383b95902dSmaxims@google.com 
3393b95902dSmaxims@google.com 	ast_scu_unlock(scu);
3403b95902dSmaxims@google.com 	writel((d2_pll_ext_param << SCU_D2PLL_EXT1_PARAM_SHIFT)
3413b95902dSmaxims@google.com 	       | SCU_D2PLL_EXT1_OFF
3423b95902dSmaxims@google.com 	       | SCU_D2PLL_EXT1_RESET, &scu->d2_pll_ext_param[0]);
3433b95902dSmaxims@google.com 
3443b95902dSmaxims@google.com 	/*
3453b95902dSmaxims@google.com 	 * Select USB2.0 port1 PHY clock as a clock source for GCRT.
3463b95902dSmaxims@google.com 	 * This would disconnect it from D2-PLL.
3473b95902dSmaxims@google.com 	 */
3483b95902dSmaxims@google.com 	clrsetbits_le32(&scu->misc_ctrl1, SCU_MISC_D2PLL_OFF,
3493b95902dSmaxims@google.com 			SCU_MISC_GCRT_USB20CLK);
3503b95902dSmaxims@google.com 
3513b95902dSmaxims@google.com 	new_rate = ast2500_calc_clock_config(clkin, rate, &div_cfg);
3523b95902dSmaxims@google.com 	writel((d2_pll_sip << SCU_D2PLL_SIP_SHIFT)
3533b95902dSmaxims@google.com 	       | (d2_pll_sic << SCU_D2PLL_SIC_SHIFT)
3543b95902dSmaxims@google.com 	       | (div_cfg.num << SCU_D2PLL_NUM_SHIFT)
3553b95902dSmaxims@google.com 	       | (div_cfg.denum << SCU_D2PLL_DENUM_SHIFT)
3563b95902dSmaxims@google.com 	       | (div_cfg.post_div << SCU_D2PLL_POST_SHIFT),
3573b95902dSmaxims@google.com 	       &scu->d2_pll_param);
3583b95902dSmaxims@google.com 
3593b95902dSmaxims@google.com 	clrbits_le32(&scu->d2_pll_ext_param[0],
3603b95902dSmaxims@google.com 		     SCU_D2PLL_EXT1_OFF | SCU_D2PLL_EXT1_RESET);
3613b95902dSmaxims@google.com 
3623b95902dSmaxims@google.com 	clrsetbits_le32(&scu->misc_ctrl2,
3633b95902dSmaxims@google.com 			SCU_MISC2_RGMII_HPLL | SCU_MISC2_RMII_MPLL
3643b95902dSmaxims@google.com 			| SCU_MISC2_RGMII_CLKDIV_MASK |
3653b95902dSmaxims@google.com 			SCU_MISC2_RMII_CLKDIV_MASK,
3663b95902dSmaxims@google.com 			(4 << SCU_MISC2_RMII_CLKDIV_SHIFT));
3673b95902dSmaxims@google.com 
3683b95902dSmaxims@google.com 	writel(clk_delay_settings | SCU_MICDS_RGMIIPLL, &scu->mac_clk_delay);
3693b95902dSmaxims@google.com 	writel(clk_delay_settings, &scu->mac_clk_delay_100M);
3703b95902dSmaxims@google.com 	writel(clk_delay_settings, &scu->mac_clk_delay_10M);
3713b95902dSmaxims@google.com 
3723b95902dSmaxims@google.com 	ast_scu_lock(scu);
3733b95902dSmaxims@google.com 
3743b95902dSmaxims@google.com 	return new_rate;
3753b95902dSmaxims@google.com }
3763b95902dSmaxims@google.com 
ast2500_clk_set_rate(struct clk * clk,ulong rate)37714e4b149Smaxims@google.com static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate)
37814e4b149Smaxims@google.com {
37914e4b149Smaxims@google.com 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
38014e4b149Smaxims@google.com 
38114e4b149Smaxims@google.com 	ulong new_rate;
38214e4b149Smaxims@google.com 	switch (clk->id) {
38314e4b149Smaxims@google.com 	case PLL_MPLL:
38414e4b149Smaxims@google.com 	case MCLK_DDR:
38514e4b149Smaxims@google.com 		new_rate = ast2500_configure_ddr(priv->scu, rate);
38614e4b149Smaxims@google.com 		break;
3873b95902dSmaxims@google.com 	case PLL_D2PLL:
3883b95902dSmaxims@google.com 		new_rate = ast2500_configure_d2pll(priv->scu, rate);
3893b95902dSmaxims@google.com 		break;
39014e4b149Smaxims@google.com 	default:
39114e4b149Smaxims@google.com 		return -ENOENT;
39214e4b149Smaxims@google.com 	}
39314e4b149Smaxims@google.com 
39414e4b149Smaxims@google.com 	return new_rate;
39514e4b149Smaxims@google.com }
39614e4b149Smaxims@google.com 
ast2500_clk_enable(struct clk * clk)3973b95902dSmaxims@google.com static int ast2500_clk_enable(struct clk *clk)
3983b95902dSmaxims@google.com {
3993b95902dSmaxims@google.com 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
4003b95902dSmaxims@google.com 
4013b95902dSmaxims@google.com 	switch (clk->id) {
4023b95902dSmaxims@google.com 	/*
4033b95902dSmaxims@google.com 	 * For MAC clocks the clock rate is
4043b95902dSmaxims@google.com 	 * configured based on whether RGMII or RMII mode has been selected
4053b95902dSmaxims@google.com 	 * through hardware strapping.
4063b95902dSmaxims@google.com 	 */
4073b95902dSmaxims@google.com 	case PCLK_MAC1:
4083b95902dSmaxims@google.com 		ast2500_configure_mac(priv->scu, 1);
4093b95902dSmaxims@google.com 		break;
4103b95902dSmaxims@google.com 	case PCLK_MAC2:
4113b95902dSmaxims@google.com 		ast2500_configure_mac(priv->scu, 2);
4123b95902dSmaxims@google.com 		break;
4133b95902dSmaxims@google.com 	case PLL_D2PLL:
4143b95902dSmaxims@google.com 		ast2500_configure_d2pll(priv->scu, D2PLL_DEFAULT_RATE);
4153b95902dSmaxims@google.com 	default:
4163b95902dSmaxims@google.com 		return -ENOENT;
4173b95902dSmaxims@google.com 	}
4183b95902dSmaxims@google.com 
4193b95902dSmaxims@google.com 	return 0;
4203b95902dSmaxims@google.com }
4213b95902dSmaxims@google.com 
42214e4b149Smaxims@google.com struct clk_ops ast2500_clk_ops = {
42314e4b149Smaxims@google.com 	.get_rate = ast2500_clk_get_rate,
42414e4b149Smaxims@google.com 	.set_rate = ast2500_clk_set_rate,
4253b95902dSmaxims@google.com 	.enable = ast2500_clk_enable,
42614e4b149Smaxims@google.com };
42714e4b149Smaxims@google.com 
ast2500_clk_probe(struct udevice * dev)42814e4b149Smaxims@google.com static int ast2500_clk_probe(struct udevice *dev)
42914e4b149Smaxims@google.com {
43014e4b149Smaxims@google.com 	struct ast2500_clk_priv *priv = dev_get_priv(dev);
43114e4b149Smaxims@google.com 
432*a821c4afSSimon Glass 	priv->scu = devfdt_get_addr_ptr(dev);
43314e4b149Smaxims@google.com 	if (IS_ERR(priv->scu))
43414e4b149Smaxims@google.com 		return PTR_ERR(priv->scu);
43514e4b149Smaxims@google.com 
43614e4b149Smaxims@google.com 	return 0;
43714e4b149Smaxims@google.com }
43814e4b149Smaxims@google.com 
ast2500_clk_bind(struct udevice * dev)43914e4b149Smaxims@google.com static int ast2500_clk_bind(struct udevice *dev)
44014e4b149Smaxims@google.com {
44114e4b149Smaxims@google.com 	int ret;
44214e4b149Smaxims@google.com 
44314e4b149Smaxims@google.com 	/* The reset driver does not have a device node, so bind it here */
44414e4b149Smaxims@google.com 	ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev);
44514e4b149Smaxims@google.com 	if (ret)
44614e4b149Smaxims@google.com 		debug("Warning: No reset driver: ret=%d\n", ret);
44714e4b149Smaxims@google.com 
44814e4b149Smaxims@google.com 	return 0;
44914e4b149Smaxims@google.com }
45014e4b149Smaxims@google.com 
45114e4b149Smaxims@google.com static const struct udevice_id ast2500_clk_ids[] = {
45214e4b149Smaxims@google.com 	{ .compatible = "aspeed,ast2500-scu" },
45314e4b149Smaxims@google.com 	{ }
45414e4b149Smaxims@google.com };
45514e4b149Smaxims@google.com 
45614e4b149Smaxims@google.com U_BOOT_DRIVER(aspeed_ast2500_scu) = {
45714e4b149Smaxims@google.com 	.name		= "aspeed_ast2500_scu",
45814e4b149Smaxims@google.com 	.id		= UCLASS_CLK,
45914e4b149Smaxims@google.com 	.of_match	= ast2500_clk_ids,
46014e4b149Smaxims@google.com 	.priv_auto_alloc_size = sizeof(struct ast2500_clk_priv),
46114e4b149Smaxims@google.com 	.ops		= &ast2500_clk_ops,
46214e4b149Smaxims@google.com 	.bind		= ast2500_clk_bind,
46314e4b149Smaxims@google.com 	.probe		= ast2500_clk_probe,
46414e4b149Smaxims@google.com };
465