1550e691bSryan_chen // SPDX-License-Identifier: GPL-2.0 2550e691bSryan_chen /* 3550e691bSryan_chen * Copyright (C) ASPEED Technology Inc. 4550e691bSryan_chen * Ryan Chen <ryan_chen@aspeedtech.com> 5550e691bSryan_chen */ 6550e691bSryan_chen 7550e691bSryan_chen #include <common.h> 8550e691bSryan_chen #include <clk-uclass.h> 9550e691bSryan_chen #include <dm.h> 10550e691bSryan_chen #include <asm/io.h> 11550e691bSryan_chen #include <dm/lists.h> 1262a6bcbfSryan_chen #include <asm/arch/scu_ast2600.h> 13d6e349c7Sryan_chen #include <dt-bindings/clock/ast2600-clock.h> 14550e691bSryan_chen 15550e691bSryan_chen /* register */ 16550e691bSryan_chen #define ASPEED_STRAP 0x70 17550e691bSryan_chen #define SCU_HWSTRAP_VGAMEM_SHIFT 2 18550e691bSryan_chen #define SCU_HWSTRAP_VGAMEM_MASK (3 << SCU_HWSTRAP_VGAMEM_SHIFT) 19550e691bSryan_chen #define SCU_HWSTRAP_MAC1_RGMII (1 << 6) 20550e691bSryan_chen #define SCU_HWSTRAP_MAC2_RGMII (1 << 7) 21550e691bSryan_chen #define SCU_HWSTRAP_DDR4 (1 << 24) 22550e691bSryan_chen #define SCU_HWSTRAP_CLKIN_25MHZ (1 << 23) 23550e691bSryan_chen 24550e691bSryan_chen #define ASPEED_CLK_SELECT 0x08 25550e691bSryan_chen #define SCU_PCLK_DIV_SHIFT 23 26550e691bSryan_chen #define SCU_PCLK_DIV_MASK (7 << SCU_PCLK_DIV_SHIFT) 27550e691bSryan_chen 28550e691bSryan_chen #define ASPEED_MSIC2 0x4C 29550e691bSryan_chen #define SCU_MISC2_RGMII_HPLL (1 << 23) 30550e691bSryan_chen #define SCU_MISC2_RGMII_CLKDIV_SHIFT 20 31550e691bSryan_chen #define SCU_MISC2_RGMII_CLKDIV_MASK (3 << SCU_MISC2_RGMII_CLKDIV_SHIFT) 32550e691bSryan_chen #define SCU_MISC2_RMII_MPLL (1 << 19) 33550e691bSryan_chen #define SCU_MISC2_RMII_CLKDIV_SHIFT 16 34550e691bSryan_chen #define SCU_MISC2_RMII_CLKDIV_MASK (3 << SCU_MISC2_RMII_CLKDIV_SHIFT) 35550e691bSryan_chen #define SCU_MISC2_UARTCLK_SHIFT 24 36550e691bSryan_chen 37550e691bSryan_chen #define ASPEED_MPLL_PARAMETER 0x20 38550e691bSryan_chen #define SCU_MPLL_DENUM_SHIFT 0 39550e691bSryan_chen #define SCU_MPLL_DENUM_MASK 0x1f 40550e691bSryan_chen #define SCU_MPLL_NUM_SHIFT 5 41550e691bSryan_chen #define SCU_MPLL_NUM_MASK (0xff << SCU_MPLL_NUM_SHIFT) 42550e691bSryan_chen #define SCU_MPLL_POST_SHIFT 13 43550e691bSryan_chen #define SCU_MPLL_POST_MASK (0x3f << SCU_MPLL_POST_SHIFT) 44550e691bSryan_chen 45550e691bSryan_chen #define ASPEED_HPLL_PARAMETER 0x24 46550e691bSryan_chen #define SCU_HPLL_DENUM_SHIFT 0 47550e691bSryan_chen #define SCU_HPLL_DENUM_MASK 0x1f 48550e691bSryan_chen #define SCU_HPLL_NUM_SHIFT 5 49550e691bSryan_chen #define SCU_HPLL_NUM_MASK (0xff << SCU_HPLL_NUM_SHIFT) 50550e691bSryan_chen #define SCU_HPLL_POST_SHIFT 13 51550e691bSryan_chen #define SCU_HPLL_POST_MASK (0x3f << SCU_HPLL_POST_SHIFT) 52550e691bSryan_chen 53550e691bSryan_chen 54550e691bSryan_chen /* 55550e691bSryan_chen * MAC Clock Delay settings, taken from Aspeed SDK 56550e691bSryan_chen */ 57550e691bSryan_chen #define RGMII_TXCLK_ODLY 8 58550e691bSryan_chen #define RMII_RXCLK_IDLY 2 59550e691bSryan_chen 60550e691bSryan_chen /* 61550e691bSryan_chen * TGMII Clock Duty constants, taken from Aspeed SDK 62550e691bSryan_chen */ 63550e691bSryan_chen #define RGMII2_TXCK_DUTY 0x66 64550e691bSryan_chen #define RGMII1_TXCK_DUTY 0x64 65550e691bSryan_chen 66550e691bSryan_chen #define D2PLL_DEFAULT_RATE (250 * 1000 * 1000) 67550e691bSryan_chen 68550e691bSryan_chen DECLARE_GLOBAL_DATA_PTR; 69550e691bSryan_chen 70550e691bSryan_chen /* 71550e691bSryan_chen * Clock divider/multiplier configuration struct. 72550e691bSryan_chen * For H-PLL and M-PLL the formula is 73550e691bSryan_chen * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1) 74550e691bSryan_chen * M - Numerator 75550e691bSryan_chen * N - Denumerator 76550e691bSryan_chen * P - Post Divider 77550e691bSryan_chen * They have the same layout in their control register. 78550e691bSryan_chen * 79550e691bSryan_chen * D-PLL and D2-PLL have extra divider (OD + 1), which is not 80550e691bSryan_chen * yet needed and ignored by clock configurations. 81550e691bSryan_chen */ 82550e691bSryan_chen struct aspeed_div_config { 83550e691bSryan_chen unsigned int num; 84550e691bSryan_chen unsigned int denum; 85550e691bSryan_chen unsigned int post_div; 86550e691bSryan_chen }; 87550e691bSryan_chen 88d6e349c7Sryan_chen #define AST2600_CLK_IN 25000000 89550e691bSryan_chen 90550e691bSryan_chen /* 91550e691bSryan_chen * Get the rate of the M-PLL clock from input clock frequency and 92550e691bSryan_chen * the value of the M-PLL Parameter Register. 93550e691bSryan_chen */ 94*f0d895afSryan_chen static u32 aspeed_get_mpll_rate(struct ast2600_clk_priv *priv) 95550e691bSryan_chen { 96d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 97*f0d895afSryan_chen u32 mpll_reg = readl(&priv->scu->m_pll_param); 98550e691bSryan_chen 99*f0d895afSryan_chen printf("&priv->scu->m_pll_param %x \n", (u32) &priv->scu->m_pll_param); 100550e691bSryan_chen const ulong num = (mpll_reg & SCU_MPLL_NUM_MASK) >> SCU_MPLL_NUM_SHIFT; 101550e691bSryan_chen const ulong denum = (mpll_reg & SCU_MPLL_DENUM_MASK) 102550e691bSryan_chen >> SCU_MPLL_DENUM_SHIFT; 103550e691bSryan_chen const ulong post_div = (mpll_reg & SCU_MPLL_POST_MASK) 104550e691bSryan_chen >> SCU_MPLL_POST_SHIFT; 105550e691bSryan_chen 106550e691bSryan_chen return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1); 107550e691bSryan_chen } 108550e691bSryan_chen 109550e691bSryan_chen /* 110550e691bSryan_chen * Get the rate of the H-PLL clock from input clock frequency and 111550e691bSryan_chen * the value of the H-PLL Parameter Register. 112550e691bSryan_chen */ 113*f0d895afSryan_chen static ulong ast2600_get_hpll_rate(struct ast2600_clk_priv *priv) 114550e691bSryan_chen { 115d6e349c7Sryan_chen ulong clkin = AST2600_CLK_IN; 116*f0d895afSryan_chen u32 hpll_reg = readl(&priv->scu->h_pll_param); 117*f0d895afSryan_chen 118*f0d895afSryan_chen printf("&priv->scu->h_pll_param %x \n", (u32) &priv->scu->h_pll_param); 119*f0d895afSryan_chen 120550e691bSryan_chen const ulong num = (hpll_reg & SCU_HPLL_NUM_MASK) >> SCU_HPLL_NUM_SHIFT; 121550e691bSryan_chen const ulong denum = (hpll_reg & SCU_HPLL_DENUM_MASK) 122550e691bSryan_chen >> SCU_HPLL_DENUM_SHIFT; 123550e691bSryan_chen const ulong post_div = (hpll_reg & SCU_HPLL_POST_MASK) 124550e691bSryan_chen >> SCU_HPLL_POST_SHIFT; 125550e691bSryan_chen 126550e691bSryan_chen return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1); 127550e691bSryan_chen } 128550e691bSryan_chen 129550e691bSryan_chen 130d6e349c7Sryan_chen #define ASPEED_G6_APLL_PARAMETER 0x210 131d6e349c7Sryan_chen #define APLL_BYPASS_EN BIT(20) 132d6e349c7Sryan_chen 133*f0d895afSryan_chen static ulong ast2600_get_apll_clk_rate(struct ast2600_clk_priv *priv) 134550e691bSryan_chen { 135d6e349c7Sryan_chen u32 clk_in = 25000000; 136*f0d895afSryan_chen u32 val = readl(&priv->scu->a_pll_param); 137d6e349c7Sryan_chen unsigned int mult, div; 138d6e349c7Sryan_chen 139*f0d895afSryan_chen printf("&priv->scu->h_pll_param %x \n", (u32) &priv->scu->a_pll_param); 140*f0d895afSryan_chen 141d6e349c7Sryan_chen if (val & APLL_BYPASS_EN) { 142d6e349c7Sryan_chen /* Pass through mode */ 143d6e349c7Sryan_chen mult = div = 1; 144d6e349c7Sryan_chen } else { 145d6e349c7Sryan_chen /* F = 25Mhz * (2-OD) * [(M + 2) / (n + 1)] */ 146d6e349c7Sryan_chen u32 m = (val >> 5) & 0x3f; 147d6e349c7Sryan_chen u32 od = (val >> 4) & 0x1; 148d6e349c7Sryan_chen u32 n = val & 0xf; 149d6e349c7Sryan_chen 150d6e349c7Sryan_chen mult = (2 - od) * (m + 2); 151d6e349c7Sryan_chen div = n + 1; 152d6e349c7Sryan_chen } 153d6e349c7Sryan_chen return (clk_in * mult)/div; 154d6e349c7Sryan_chen 155d6e349c7Sryan_chen 156d6e349c7Sryan_chen 157d6e349c7Sryan_chen } 158d6e349c7Sryan_chen 159*f0d895afSryan_chen //#define ASPEED_G6_CLK_SELECT4 0x314 160d6e349c7Sryan_chen 161*f0d895afSryan_chen static ulong ast2600_get_uart_clk_rate(struct ast2600_clk_priv *priv, int uart_index) 162d6e349c7Sryan_chen { 163550e691bSryan_chen ulong uart_clkin; 164550e691bSryan_chen 165*f0d895afSryan_chen printf("ast2600_get_uart_clk_rate source %ld \n\n", ast2600_get_apll_clk_rate(priv)); 166d6e349c7Sryan_chen return (24000000/13); 167d6e349c7Sryan_chen 168*f0d895afSryan_chen if (readl(&priv->scu->misc_ctrl2) & 169550e691bSryan_chen (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT))) 170550e691bSryan_chen uart_clkin = 192 * 1000 * 1000; 171550e691bSryan_chen else 172550e691bSryan_chen uart_clkin = 24 * 1000 * 1000; 173550e691bSryan_chen 174*f0d895afSryan_chen if (readl(&priv->scu->misc_ctrl2) & SCU_MISC_UARTCLK_DIV13) 175550e691bSryan_chen uart_clkin /= 13; 176550e691bSryan_chen 177550e691bSryan_chen return uart_clkin; 178550e691bSryan_chen } 179550e691bSryan_chen 180550e691bSryan_chen struct aspeed_clock_config { 181550e691bSryan_chen ulong input_rate; 182550e691bSryan_chen ulong rate; 183550e691bSryan_chen struct aspeed_div_config cfg; 184550e691bSryan_chen }; 185550e691bSryan_chen 186550e691bSryan_chen static const struct aspeed_clock_config aspeed_clock_config_defaults[] = { 187550e691bSryan_chen { 24000000, 250000000, { .num = 124, .denum = 1, .post_div = 5 } }, 188550e691bSryan_chen }; 189550e691bSryan_chen 190550e691bSryan_chen static bool aspeed_get_clock_config_default(ulong input_rate, 191550e691bSryan_chen ulong requested_rate, 192550e691bSryan_chen struct aspeed_div_config *cfg) 193550e691bSryan_chen { 194550e691bSryan_chen int i; 195550e691bSryan_chen 196550e691bSryan_chen for (i = 0; i < ARRAY_SIZE(aspeed_clock_config_defaults); i++) { 197550e691bSryan_chen const struct aspeed_clock_config *default_cfg = 198550e691bSryan_chen &aspeed_clock_config_defaults[i]; 199550e691bSryan_chen if (default_cfg->input_rate == input_rate && 200550e691bSryan_chen default_cfg->rate == requested_rate) { 201550e691bSryan_chen *cfg = default_cfg->cfg; 202550e691bSryan_chen return true; 203550e691bSryan_chen } 204550e691bSryan_chen } 205550e691bSryan_chen 206550e691bSryan_chen return false; 207550e691bSryan_chen } 208550e691bSryan_chen 209550e691bSryan_chen /* 210550e691bSryan_chen * @input_rate - the rate of input clock in Hz 211550e691bSryan_chen * @requested_rate - desired output rate in Hz 212550e691bSryan_chen * @div - this is an IN/OUT parameter, at input all fields of the config 213550e691bSryan_chen * need to be set to their maximum allowed values. 214550e691bSryan_chen * The result (the best config we could find), would also be returned 215550e691bSryan_chen * in this structure. 216550e691bSryan_chen * 217550e691bSryan_chen * @return The clock rate, when the resulting div_config is used. 218550e691bSryan_chen */ 219550e691bSryan_chen static ulong aspeed_calc_clock_config(ulong input_rate, ulong requested_rate, 220550e691bSryan_chen struct aspeed_div_config *cfg) 221550e691bSryan_chen { 222550e691bSryan_chen /* 223550e691bSryan_chen * The assumption is that kHz precision is good enough and 224550e691bSryan_chen * also enough to avoid overflow when multiplying. 225550e691bSryan_chen */ 226550e691bSryan_chen const ulong input_rate_khz = input_rate / 1000; 227550e691bSryan_chen const ulong rate_khz = requested_rate / 1000; 228550e691bSryan_chen const struct aspeed_div_config max_vals = *cfg; 229550e691bSryan_chen struct aspeed_div_config it = { 0, 0, 0 }; 230550e691bSryan_chen ulong delta = rate_khz; 231550e691bSryan_chen ulong new_rate_khz = 0; 232550e691bSryan_chen 233550e691bSryan_chen /* 234550e691bSryan_chen * Look for a well known frequency first. 235550e691bSryan_chen */ 236550e691bSryan_chen if (aspeed_get_clock_config_default(input_rate, requested_rate, cfg)) 237550e691bSryan_chen return requested_rate; 238550e691bSryan_chen 239550e691bSryan_chen for (; it.denum <= max_vals.denum; ++it.denum) { 240550e691bSryan_chen for (it.post_div = 0; it.post_div <= max_vals.post_div; 241550e691bSryan_chen ++it.post_div) { 242550e691bSryan_chen it.num = (rate_khz * (it.post_div + 1) / input_rate_khz) 243550e691bSryan_chen * (it.denum + 1); 244550e691bSryan_chen if (it.num > max_vals.num) 245550e691bSryan_chen continue; 246550e691bSryan_chen 247550e691bSryan_chen new_rate_khz = (input_rate_khz 248550e691bSryan_chen * ((it.num + 1) / (it.denum + 1))) 249550e691bSryan_chen / (it.post_div + 1); 250550e691bSryan_chen 251550e691bSryan_chen /* Keep the rate below requested one. */ 252550e691bSryan_chen if (new_rate_khz > rate_khz) 253550e691bSryan_chen continue; 254550e691bSryan_chen 255550e691bSryan_chen if (new_rate_khz - rate_khz < delta) { 256550e691bSryan_chen delta = new_rate_khz - rate_khz; 257550e691bSryan_chen *cfg = it; 258550e691bSryan_chen if (delta == 0) 259550e691bSryan_chen return new_rate_khz * 1000; 260550e691bSryan_chen } 261550e691bSryan_chen } 262550e691bSryan_chen } 263550e691bSryan_chen 264550e691bSryan_chen return new_rate_khz * 1000; 265550e691bSryan_chen } 266550e691bSryan_chen 267*f0d895afSryan_chen static u32 aspeed_configure_ddr(struct ast2600_clk_priv *priv, ulong rate) 268550e691bSryan_chen { 269d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 270550e691bSryan_chen u32 mpll_reg; 271550e691bSryan_chen struct aspeed_div_config div_cfg = { 272550e691bSryan_chen .num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT), 273550e691bSryan_chen .denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT), 274550e691bSryan_chen .post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT), 275550e691bSryan_chen }; 276550e691bSryan_chen 277550e691bSryan_chen aspeed_calc_clock_config(clkin, rate, &div_cfg); 278550e691bSryan_chen 279*f0d895afSryan_chen mpll_reg = readl(&priv->scu->m_pll_param); 280550e691bSryan_chen mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK 281550e691bSryan_chen | SCU_MPLL_DENUM_MASK); 282550e691bSryan_chen mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT) 283550e691bSryan_chen | (div_cfg.num << SCU_MPLL_NUM_SHIFT) 284550e691bSryan_chen | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT); 285550e691bSryan_chen 286*f0d895afSryan_chen writel(mpll_reg, &priv->scu->m_pll_param); 287550e691bSryan_chen 288550e691bSryan_chen return aspeed_get_mpll_rate(priv); 289550e691bSryan_chen } 290550e691bSryan_chen 291*f0d895afSryan_chen static u32 aspeed_configure_mac(struct ast2600_clk_priv *priv, int index) 292550e691bSryan_chen { 293*f0d895afSryan_chen #if 0 294*f0d895afSryan_chen 295d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 29662a6bcbfSryan_chen u32 hpll_rate = ast2600_get_hpll_rate(priv); 297550e691bSryan_chen ulong required_rate; 298550e691bSryan_chen u32 hwstrap; 299550e691bSryan_chen u32 divisor; 300550e691bSryan_chen u32 reset_bit; 301550e691bSryan_chen u32 clkstop_bit; 302*f0d895afSryan_chen 303550e691bSryan_chen /* 304550e691bSryan_chen * According to data sheet, for 10/100 mode the MAC clock frequency 305550e691bSryan_chen * should be at least 25MHz and for 1000 mode at least 100MHz 306550e691bSryan_chen */ 307550e691bSryan_chen hwstrap = readl(priv->regs + ASPEED_STRAP); 308550e691bSryan_chen if (hwstrap & (SCU_HWSTRAP_MAC1_RGMII | SCU_HWSTRAP_MAC2_RGMII)) 309550e691bSryan_chen required_rate = 100 * 1000 * 1000; 310550e691bSryan_chen else 311550e691bSryan_chen required_rate = 25 * 1000 * 1000; 312550e691bSryan_chen 313550e691bSryan_chen divisor = hpll_rate / required_rate; 314550e691bSryan_chen 315550e691bSryan_chen if (divisor < 4) { 316550e691bSryan_chen /* Clock can't run fast enough, but let's try anyway */ 317550e691bSryan_chen debug("MAC clock too slow\n"); 318550e691bSryan_chen divisor = 4; 319550e691bSryan_chen } else if (divisor > 16) { 320550e691bSryan_chen /* Can't slow down the clock enough, but let's try anyway */ 321550e691bSryan_chen debug("MAC clock too fast\n"); 322550e691bSryan_chen divisor = 16; 323550e691bSryan_chen } 324550e691bSryan_chen 325550e691bSryan_chen switch (index) { 326550e691bSryan_chen case 1: 327550e691bSryan_chen reset_bit = SCU_SYSRESET_MAC1; 328550e691bSryan_chen clkstop_bit = SCU_CLKSTOP_MAC1; 329550e691bSryan_chen break; 330550e691bSryan_chen case 2: 331550e691bSryan_chen reset_bit = SCU_SYSRESET_MAC2; 332550e691bSryan_chen clkstop_bit = SCU_CLKSTOP_MAC2; 333550e691bSryan_chen break; 334550e691bSryan_chen default: 335550e691bSryan_chen return -EINVAL; 336550e691bSryan_chen } 337550e691bSryan_chen 338550e691bSryan_chen clrsetbits_le32(priv->regs + ASPEED_CLK_SELECT, SCU_MACCLK_MASK, 339550e691bSryan_chen ((divisor - 2) / 2) << SCU_MACCLK_SHIFT); 340550e691bSryan_chen 341550e691bSryan_chen /* 342550e691bSryan_chen * Disable MAC, start its clock and re-enable it. 343550e691bSryan_chen * The procedure and the delays (100us & 10ms) are 344550e691bSryan_chen * specified in the datasheet. 345550e691bSryan_chen */ 346550e691bSryan_chen setbits_le32(&scu->sysreset_ctrl1, reset_bit); 347550e691bSryan_chen udelay(100); 348550e691bSryan_chen clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit); 349550e691bSryan_chen mdelay(10); 350550e691bSryan_chen clrbits_le32(&scu->sysreset_ctrl1, reset_bit); 351550e691bSryan_chen 352550e691bSryan_chen writel((RGMII2_TXCK_DUTY << SCU_CLKDUTY_RGMII2TXCK_SHIFT) 353550e691bSryan_chen | (RGMII1_TXCK_DUTY << SCU_CLKDUTY_RGMII1TXCK_SHIFT), 354550e691bSryan_chen &scu->clk_duty_sel); 355*f0d895afSryan_chen 356550e691bSryan_chen return required_rate; 357*f0d895afSryan_chen #endif 358550e691bSryan_chen } 359550e691bSryan_chen 360*f0d895afSryan_chen static ulong aspeed_configure_d2pll(struct ast2600_clk_priv *priv, ulong rate) 361550e691bSryan_chen { 362550e691bSryan_chen /* 363550e691bSryan_chen * The values and the meaning of the next three 364550e691bSryan_chen * parameters are undocumented. Taken from Aspeed SDK. 365550e691bSryan_chen * 366550e691bSryan_chen * TODO(clg@kaod.org): the SIP and SIC values depend on the 367550e691bSryan_chen * Numerator value 368550e691bSryan_chen */ 369550e691bSryan_chen 370550e691bSryan_chen const u32 d2_pll_ext_param = 0x2c; 371550e691bSryan_chen const u32 d2_pll_sip = 0x11; 372550e691bSryan_chen const u32 d2_pll_sic = 0x18; 373550e691bSryan_chen u32 clk_delay_settings = 374550e691bSryan_chen (RMII_RXCLK_IDLY << SCU_MICDS_MAC1RMII_RDLY_SHIFT) 375550e691bSryan_chen | (RMII_RXCLK_IDLY << SCU_MICDS_MAC2RMII_RDLY_SHIFT) 376550e691bSryan_chen | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC1RGMII_TXDLY_SHIFT) 377550e691bSryan_chen | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC2RGMII_TXDLY_SHIFT); 378550e691bSryan_chen struct aspeed_div_config div_cfg = { 379550e691bSryan_chen .num = SCU_D2PLL_NUM_MASK >> SCU_D2PLL_NUM_SHIFT, 380550e691bSryan_chen .denum = SCU_D2PLL_DENUM_MASK >> SCU_D2PLL_DENUM_SHIFT, 381550e691bSryan_chen .post_div = SCU_D2PLL_POST_MASK >> SCU_D2PLL_POST_SHIFT, 382550e691bSryan_chen }; 383d6e349c7Sryan_chen ulong clkin = AST2600_CLK_IN; 384550e691bSryan_chen ulong new_rate; 385550e691bSryan_chen #if 0 386550e691bSryan_chen writel((d2_pll_ext_param << SCU_D2PLL_EXT1_PARAM_SHIFT) 387550e691bSryan_chen | SCU_D2PLL_EXT1_OFF 388550e691bSryan_chen | SCU_D2PLL_EXT1_RESET, &scu->d2_pll_ext_param[0]); 389550e691bSryan_chen 390550e691bSryan_chen /* 391550e691bSryan_chen * Select USB2.0 port1 PHY clock as a clock source for GCRT. 392550e691bSryan_chen * This would disconnect it from D2-PLL. 393550e691bSryan_chen */ 394550e691bSryan_chen clrsetbits_le32(&scu->misc_ctrl1, SCU_MISC_D2PLL_OFF, 395550e691bSryan_chen SCU_MISC_GCRT_USB20CLK); 396550e691bSryan_chen 397550e691bSryan_chen new_rate = aspeed_calc_clock_config(clkin, rate, &div_cfg); 398550e691bSryan_chen writel((d2_pll_sip << SCU_D2PLL_SIP_SHIFT) 399550e691bSryan_chen | (d2_pll_sic << SCU_D2PLL_SIC_SHIFT) 400550e691bSryan_chen | (div_cfg.num << SCU_D2PLL_NUM_SHIFT) 401550e691bSryan_chen | (div_cfg.denum << SCU_D2PLL_DENUM_SHIFT) 402550e691bSryan_chen | (div_cfg.post_div << SCU_D2PLL_POST_SHIFT), 403550e691bSryan_chen &scu->d2_pll_param); 404550e691bSryan_chen 405550e691bSryan_chen clrbits_le32(&scu->d2_pll_ext_param[0], 406550e691bSryan_chen SCU_D2PLL_EXT1_OFF | SCU_D2PLL_EXT1_RESET); 407550e691bSryan_chen 408550e691bSryan_chen clrsetbits_le32(&scu->misc_ctrl2, 409550e691bSryan_chen SCU_MISC2_RGMII_HPLL | SCU_MISC2_RMII_MPLL 410550e691bSryan_chen | SCU_MISC2_RGMII_CLKDIV_MASK | 411550e691bSryan_chen SCU_MISC2_RMII_CLKDIV_MASK, 412550e691bSryan_chen (4 << SCU_MISC2_RMII_CLKDIV_SHIFT)); 413550e691bSryan_chen 414550e691bSryan_chen writel(clk_delay_settings | SCU_MICDS_RGMIIPLL, &scu->mac_clk_delay); 415550e691bSryan_chen writel(clk_delay_settings, &scu->mac_clk_delay_100M); 416550e691bSryan_chen writel(clk_delay_settings, &scu->mac_clk_delay_10M); 417550e691bSryan_chen #endif 418550e691bSryan_chen return new_rate; 419550e691bSryan_chen } 420550e691bSryan_chen 421*f0d895afSryan_chen static u32 ast2600_a0_axi_ahb_div_table[] = { 422*f0d895afSryan_chen 2, 2, 3, 5, 423*f0d895afSryan_chen }; 424*f0d895afSryan_chen 425*f0d895afSryan_chen static u32 ast2600_a1_axi_ahb_div_table[] = { 426*f0d895afSryan_chen 4, 6, 2, 4, 427*f0d895afSryan_chen }; 428*f0d895afSryan_chen 429*f0d895afSryan_chen static u32 ast2600_hpll_pclk_div_table[] = { 430*f0d895afSryan_chen 4, 8, 12, 16, 20, 24, 28, 32, 431*f0d895afSryan_chen }; 432d6e349c7Sryan_chen static ulong ast2600_clk_get_rate(struct clk *clk) 433d6e349c7Sryan_chen { 434*f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 435d6e349c7Sryan_chen ulong rate; 436d6e349c7Sryan_chen 437d6e349c7Sryan_chen switch (clk->id) { 438d1e64dd1Sryan_chen //HPLL 439d1e64dd1Sryan_chen case ASPEED_CLK_HPLL: 44062a6bcbfSryan_chen rate = ast2600_get_hpll_rate(priv); 441d6e349c7Sryan_chen break; 442d1e64dd1Sryan_chen //HCLK 443d1e64dd1Sryan_chen case ASPEED_CLK_AHB: 44462a6bcbfSryan_chen { 445*f0d895afSryan_chen u32 hw_rev = readl(&priv->scu->chip_id0); 446*f0d895afSryan_chen u32 hwstrap1 = readl(&priv->scu->hwstrap1); 447*f0d895afSryan_chen u32 axi_div = 1; 448*f0d895afSryan_chen u32 ahb_div = 0; 449*f0d895afSryan_chen if((hwstrap1 >> 16) & 0x1) 450*f0d895afSryan_chen axi_div = 1; 451*f0d895afSryan_chen else 452*f0d895afSryan_chen axi_div = 2; 45362a6bcbfSryan_chen 454*f0d895afSryan_chen if (hw_rev & BIT(16)) 455*f0d895afSryan_chen ahb_div = ast2600_a1_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 456*f0d895afSryan_chen else 457*f0d895afSryan_chen ahb_div = ast2600_a0_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 458*f0d895afSryan_chen 459*f0d895afSryan_chen rate = ast2600_get_hpll_rate(priv); 46062a6bcbfSryan_chen rate = rate / axi_div / ahb_div; 46162a6bcbfSryan_chen } 462d1e64dd1Sryan_chen break; 463d1e64dd1Sryan_chen 464*f0d895afSryan_chen case ASPEED_CLK_MPLL: 465d6e349c7Sryan_chen rate = aspeed_get_mpll_rate(priv); 466d6e349c7Sryan_chen break; 467d6e349c7Sryan_chen case BCLK_PCLK: 468d6e349c7Sryan_chen { 469*f0d895afSryan_chen u32 clk_sel1 = readl(&priv->scu->clk_sel1); 470*f0d895afSryan_chen u32 apb_div = ast2600_hpll_pclk_div_table[((clk_sel1 >> 23) & 0x7)]; 47162a6bcbfSryan_chen rate = ast2600_get_hpll_rate(priv); 472d6e349c7Sryan_chen rate = rate / apb_div; 473d6e349c7Sryan_chen } 474d6e349c7Sryan_chen break; 475d6e349c7Sryan_chen case PCLK_UART1: 476d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 1); 477d6e349c7Sryan_chen break; 478d6e349c7Sryan_chen case PCLK_UART2: 479d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 2); 480d6e349c7Sryan_chen break; 481d6e349c7Sryan_chen case PCLK_UART3: 482d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 3); 483d6e349c7Sryan_chen break; 484d6e349c7Sryan_chen case PCLK_UART4: 485d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 4); 486d6e349c7Sryan_chen break; 487d1e64dd1Sryan_chen case ASPEED_CLK_GATE_UART5CLK: 488d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 5); 489d6e349c7Sryan_chen break; 490d6e349c7Sryan_chen default: 491d6e349c7Sryan_chen return -ENOENT; 492d6e349c7Sryan_chen } 493d6e349c7Sryan_chen 494d6e349c7Sryan_chen return rate; 495d6e349c7Sryan_chen } 496d6e349c7Sryan_chen 497d6e349c7Sryan_chen static ulong ast2600_clk_set_rate(struct clk *clk, ulong rate) 498550e691bSryan_chen { 499*f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 500550e691bSryan_chen 501550e691bSryan_chen ulong new_rate; 502550e691bSryan_chen switch (clk->id) { 503*f0d895afSryan_chen case ASPEED_CLK_MPLL: 504550e691bSryan_chen new_rate = aspeed_configure_ddr(priv, rate); 505550e691bSryan_chen break; 506550e691bSryan_chen case PLL_D2PLL: 507550e691bSryan_chen new_rate = aspeed_configure_d2pll(priv, rate); 508550e691bSryan_chen break; 509550e691bSryan_chen default: 510550e691bSryan_chen return -ENOENT; 511550e691bSryan_chen } 512550e691bSryan_chen 513550e691bSryan_chen return new_rate; 514550e691bSryan_chen } 515550e691bSryan_chen 516d6e349c7Sryan_chen static int ast2600_clk_enable(struct clk *clk) 517550e691bSryan_chen { 518*f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 519550e691bSryan_chen 520550e691bSryan_chen switch (clk->id) { 521550e691bSryan_chen /* 522550e691bSryan_chen * For MAC clocks the clock rate is 523550e691bSryan_chen * configured based on whether RGMII or RMII mode has been selected 524550e691bSryan_chen * through hardware strapping. 525550e691bSryan_chen */ 526550e691bSryan_chen case PCLK_MAC1: 527550e691bSryan_chen aspeed_configure_mac(priv, 1); 528550e691bSryan_chen break; 529550e691bSryan_chen case PCLK_MAC2: 530550e691bSryan_chen aspeed_configure_mac(priv, 2); 531550e691bSryan_chen break; 532550e691bSryan_chen case PLL_D2PLL: 533550e691bSryan_chen aspeed_configure_d2pll(priv, D2PLL_DEFAULT_RATE); 534550e691bSryan_chen break; 535550e691bSryan_chen default: 536550e691bSryan_chen return -ENOENT; 537550e691bSryan_chen } 538550e691bSryan_chen 539550e691bSryan_chen return 0; 540550e691bSryan_chen } 541550e691bSryan_chen 542550e691bSryan_chen struct clk_ops aspeed_clk_ops = { 543d6e349c7Sryan_chen .get_rate = ast2600_clk_get_rate, 544d6e349c7Sryan_chen .set_rate = ast2600_clk_set_rate, 545d6e349c7Sryan_chen .enable = ast2600_clk_enable, 546550e691bSryan_chen }; 547550e691bSryan_chen 548d6e349c7Sryan_chen static int ast2600_clk_probe(struct udevice *dev) 549550e691bSryan_chen { 550*f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(dev); 551550e691bSryan_chen 552*f0d895afSryan_chen priv->scu = devfdt_get_addr_ptr(dev); 553*f0d895afSryan_chen if (IS_ERR(priv->scu)) 554*f0d895afSryan_chen return PTR_ERR(priv->scu); 555550e691bSryan_chen 556550e691bSryan_chen return 0; 557550e691bSryan_chen } 558550e691bSryan_chen 559d6e349c7Sryan_chen static int ast2600_clk_bind(struct udevice *dev) 560550e691bSryan_chen { 561550e691bSryan_chen int ret; 562550e691bSryan_chen 563550e691bSryan_chen /* The reset driver does not have a device node, so bind it here */ 564550e691bSryan_chen ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev); 565550e691bSryan_chen if (ret) 566550e691bSryan_chen debug("Warning: No reset driver: ret=%d\n", ret); 567550e691bSryan_chen 568550e691bSryan_chen return 0; 569550e691bSryan_chen } 570550e691bSryan_chen 571d6e349c7Sryan_chen static const struct udevice_id ast2600_clk_ids[] = { 572d6e349c7Sryan_chen { .compatible = "aspeed,ast2600-scu", }, 573550e691bSryan_chen { } 574550e691bSryan_chen }; 575550e691bSryan_chen 576aa36597fSDylan Hung U_BOOT_DRIVER(aspeed_scu) = { 577aa36597fSDylan Hung .name = "aspeed_scu", 578550e691bSryan_chen .id = UCLASS_CLK, 579d6e349c7Sryan_chen .of_match = ast2600_clk_ids, 580*f0d895afSryan_chen .priv_auto_alloc_size = sizeof(struct ast2600_clk_priv), 581550e691bSryan_chen .ops = &aspeed_clk_ops, 582d6e349c7Sryan_chen .bind = ast2600_clk_bind, 583d6e349c7Sryan_chen .probe = ast2600_clk_probe, 584550e691bSryan_chen }; 585