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