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> 12*62a6bcbfSryan_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 */ 94550e691bSryan_chen static u32 aspeed_get_mpll_rate(struct aspeed_clk_priv *priv) 95550e691bSryan_chen { 96d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 97550e691bSryan_chen u32 mpll_reg = readl(priv->regs + ASPEED_MPLL_PARAMETER); 98550e691bSryan_chen 99550e691bSryan_chen const ulong num = (mpll_reg & SCU_MPLL_NUM_MASK) >> SCU_MPLL_NUM_SHIFT; 100550e691bSryan_chen const ulong denum = (mpll_reg & SCU_MPLL_DENUM_MASK) 101550e691bSryan_chen >> SCU_MPLL_DENUM_SHIFT; 102550e691bSryan_chen const ulong post_div = (mpll_reg & SCU_MPLL_POST_MASK) 103550e691bSryan_chen >> SCU_MPLL_POST_SHIFT; 104550e691bSryan_chen 105550e691bSryan_chen return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1); 106550e691bSryan_chen } 107550e691bSryan_chen 108550e691bSryan_chen /* 109550e691bSryan_chen * Get the rate of the H-PLL clock from input clock frequency and 110550e691bSryan_chen * the value of the H-PLL Parameter Register. 111550e691bSryan_chen */ 112*62a6bcbfSryan_chen static ulong ast2600_get_hpll_rate(struct aspeed_clk_priv *priv) 113550e691bSryan_chen { 114d6e349c7Sryan_chen ulong clkin = AST2600_CLK_IN; 115550e691bSryan_chen u32 hpll_reg = readl(priv->regs + ASPEED_HPLL_PARAMETER); 116550e691bSryan_chen const ulong num = (hpll_reg & SCU_HPLL_NUM_MASK) >> SCU_HPLL_NUM_SHIFT; 117550e691bSryan_chen const ulong denum = (hpll_reg & SCU_HPLL_DENUM_MASK) 118550e691bSryan_chen >> SCU_HPLL_DENUM_SHIFT; 119550e691bSryan_chen const ulong post_div = (hpll_reg & SCU_HPLL_POST_MASK) 120550e691bSryan_chen >> SCU_HPLL_POST_SHIFT; 121550e691bSryan_chen 122550e691bSryan_chen return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1); 123550e691bSryan_chen } 124550e691bSryan_chen 125550e691bSryan_chen 126d6e349c7Sryan_chen #define ASPEED_G6_APLL_PARAMETER 0x210 127d6e349c7Sryan_chen #define APLL_BYPASS_EN BIT(20) 128d6e349c7Sryan_chen 129d6e349c7Sryan_chen static ulong ast2600_get_apll_clk_rate(struct aspeed_clk_priv *priv) 130550e691bSryan_chen { 131d6e349c7Sryan_chen u32 clk_in = 25000000; 132d6e349c7Sryan_chen u32 val = readl(priv->regs + ASPEED_G6_APLL_PARAMETER); 133d6e349c7Sryan_chen 134d6e349c7Sryan_chen 135d6e349c7Sryan_chen unsigned int mult, div; 136d6e349c7Sryan_chen 137d6e349c7Sryan_chen if (val & APLL_BYPASS_EN) { 138d6e349c7Sryan_chen /* Pass through mode */ 139d6e349c7Sryan_chen mult = div = 1; 140d6e349c7Sryan_chen } else { 141d6e349c7Sryan_chen /* F = 25Mhz * (2-OD) * [(M + 2) / (n + 1)] */ 142d6e349c7Sryan_chen u32 m = (val >> 5) & 0x3f; 143d6e349c7Sryan_chen u32 od = (val >> 4) & 0x1; 144d6e349c7Sryan_chen u32 n = val & 0xf; 145d6e349c7Sryan_chen 146d6e349c7Sryan_chen mult = (2 - od) * (m + 2); 147d6e349c7Sryan_chen div = n + 1; 148d6e349c7Sryan_chen } 149d6e349c7Sryan_chen return (clk_in * mult)/div; 150d6e349c7Sryan_chen 151d6e349c7Sryan_chen 152d6e349c7Sryan_chen 153d6e349c7Sryan_chen } 154d6e349c7Sryan_chen 155d6e349c7Sryan_chen #define ASPEED_G6_CLK_SELECT4 0x314 156d6e349c7Sryan_chen 157d6e349c7Sryan_chen static ulong ast2600_get_uart_clk_rate(struct aspeed_clk_priv *priv, int uart_index) 158d6e349c7Sryan_chen { 159550e691bSryan_chen ulong uart_clkin; 160550e691bSryan_chen 161d6e349c7Sryan_chen printf("ast2600_get_uart_clk_rate source %d \n\n", ast2600_get_apll_clk_rate(priv)); 162d6e349c7Sryan_chen return (24000000/13); 163d6e349c7Sryan_chen 164550e691bSryan_chen if (readl(priv->regs + ASPEED_MSIC2) & 165550e691bSryan_chen (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT))) 166550e691bSryan_chen uart_clkin = 192 * 1000 * 1000; 167550e691bSryan_chen else 168550e691bSryan_chen uart_clkin = 24 * 1000 * 1000; 169550e691bSryan_chen 170550e691bSryan_chen if (readl(priv->regs + ASPEED_MSIC2) & SCU_MISC_UARTCLK_DIV13) 171550e691bSryan_chen uart_clkin /= 13; 172550e691bSryan_chen 173550e691bSryan_chen return uart_clkin; 174550e691bSryan_chen } 175550e691bSryan_chen 176550e691bSryan_chen struct aspeed_clock_config { 177550e691bSryan_chen ulong input_rate; 178550e691bSryan_chen ulong rate; 179550e691bSryan_chen struct aspeed_div_config cfg; 180550e691bSryan_chen }; 181550e691bSryan_chen 182550e691bSryan_chen static const struct aspeed_clock_config aspeed_clock_config_defaults[] = { 183550e691bSryan_chen { 24000000, 250000000, { .num = 124, .denum = 1, .post_div = 5 } }, 184550e691bSryan_chen }; 185550e691bSryan_chen 186550e691bSryan_chen static bool aspeed_get_clock_config_default(ulong input_rate, 187550e691bSryan_chen ulong requested_rate, 188550e691bSryan_chen struct aspeed_div_config *cfg) 189550e691bSryan_chen { 190550e691bSryan_chen int i; 191550e691bSryan_chen 192550e691bSryan_chen for (i = 0; i < ARRAY_SIZE(aspeed_clock_config_defaults); i++) { 193550e691bSryan_chen const struct aspeed_clock_config *default_cfg = 194550e691bSryan_chen &aspeed_clock_config_defaults[i]; 195550e691bSryan_chen if (default_cfg->input_rate == input_rate && 196550e691bSryan_chen default_cfg->rate == requested_rate) { 197550e691bSryan_chen *cfg = default_cfg->cfg; 198550e691bSryan_chen return true; 199550e691bSryan_chen } 200550e691bSryan_chen } 201550e691bSryan_chen 202550e691bSryan_chen return false; 203550e691bSryan_chen } 204550e691bSryan_chen 205550e691bSryan_chen /* 206550e691bSryan_chen * @input_rate - the rate of input clock in Hz 207550e691bSryan_chen * @requested_rate - desired output rate in Hz 208550e691bSryan_chen * @div - this is an IN/OUT parameter, at input all fields of the config 209550e691bSryan_chen * need to be set to their maximum allowed values. 210550e691bSryan_chen * The result (the best config we could find), would also be returned 211550e691bSryan_chen * in this structure. 212550e691bSryan_chen * 213550e691bSryan_chen * @return The clock rate, when the resulting div_config is used. 214550e691bSryan_chen */ 215550e691bSryan_chen static ulong aspeed_calc_clock_config(ulong input_rate, ulong requested_rate, 216550e691bSryan_chen struct aspeed_div_config *cfg) 217550e691bSryan_chen { 218550e691bSryan_chen /* 219550e691bSryan_chen * The assumption is that kHz precision is good enough and 220550e691bSryan_chen * also enough to avoid overflow when multiplying. 221550e691bSryan_chen */ 222550e691bSryan_chen const ulong input_rate_khz = input_rate / 1000; 223550e691bSryan_chen const ulong rate_khz = requested_rate / 1000; 224550e691bSryan_chen const struct aspeed_div_config max_vals = *cfg; 225550e691bSryan_chen struct aspeed_div_config it = { 0, 0, 0 }; 226550e691bSryan_chen ulong delta = rate_khz; 227550e691bSryan_chen ulong new_rate_khz = 0; 228550e691bSryan_chen 229550e691bSryan_chen /* 230550e691bSryan_chen * Look for a well known frequency first. 231550e691bSryan_chen */ 232550e691bSryan_chen if (aspeed_get_clock_config_default(input_rate, requested_rate, cfg)) 233550e691bSryan_chen return requested_rate; 234550e691bSryan_chen 235550e691bSryan_chen for (; it.denum <= max_vals.denum; ++it.denum) { 236550e691bSryan_chen for (it.post_div = 0; it.post_div <= max_vals.post_div; 237550e691bSryan_chen ++it.post_div) { 238550e691bSryan_chen it.num = (rate_khz * (it.post_div + 1) / input_rate_khz) 239550e691bSryan_chen * (it.denum + 1); 240550e691bSryan_chen if (it.num > max_vals.num) 241550e691bSryan_chen continue; 242550e691bSryan_chen 243550e691bSryan_chen new_rate_khz = (input_rate_khz 244550e691bSryan_chen * ((it.num + 1) / (it.denum + 1))) 245550e691bSryan_chen / (it.post_div + 1); 246550e691bSryan_chen 247550e691bSryan_chen /* Keep the rate below requested one. */ 248550e691bSryan_chen if (new_rate_khz > rate_khz) 249550e691bSryan_chen continue; 250550e691bSryan_chen 251550e691bSryan_chen if (new_rate_khz - rate_khz < delta) { 252550e691bSryan_chen delta = new_rate_khz - rate_khz; 253550e691bSryan_chen *cfg = it; 254550e691bSryan_chen if (delta == 0) 255550e691bSryan_chen return new_rate_khz * 1000; 256550e691bSryan_chen } 257550e691bSryan_chen } 258550e691bSryan_chen } 259550e691bSryan_chen 260550e691bSryan_chen return new_rate_khz * 1000; 261550e691bSryan_chen } 262550e691bSryan_chen 263550e691bSryan_chen static u32 aspeed_configure_ddr(struct aspeed_clk_priv *priv, ulong rate) 264550e691bSryan_chen { 265d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 266550e691bSryan_chen u32 mpll_reg; 267550e691bSryan_chen struct aspeed_div_config div_cfg = { 268550e691bSryan_chen .num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT), 269550e691bSryan_chen .denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT), 270550e691bSryan_chen .post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT), 271550e691bSryan_chen }; 272550e691bSryan_chen 273550e691bSryan_chen aspeed_calc_clock_config(clkin, rate, &div_cfg); 274550e691bSryan_chen 275550e691bSryan_chen mpll_reg = readl(priv->regs + ASPEED_MPLL_PARAMETER); 276550e691bSryan_chen mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK 277550e691bSryan_chen | SCU_MPLL_DENUM_MASK); 278550e691bSryan_chen mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT) 279550e691bSryan_chen | (div_cfg.num << SCU_MPLL_NUM_SHIFT) 280550e691bSryan_chen | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT); 281550e691bSryan_chen 282550e691bSryan_chen writel(mpll_reg, priv->regs + ASPEED_MPLL_PARAMETER); 283550e691bSryan_chen 284550e691bSryan_chen return aspeed_get_mpll_rate(priv); 285550e691bSryan_chen } 286550e691bSryan_chen 287550e691bSryan_chen static u32 aspeed_configure_mac(struct aspeed_clk_priv *priv, int index) 288550e691bSryan_chen { 289d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 290*62a6bcbfSryan_chen u32 hpll_rate = ast2600_get_hpll_rate(priv); 291550e691bSryan_chen ulong required_rate; 292550e691bSryan_chen u32 hwstrap; 293550e691bSryan_chen u32 divisor; 294550e691bSryan_chen u32 reset_bit; 295550e691bSryan_chen u32 clkstop_bit; 296550e691bSryan_chen #if 0 297550e691bSryan_chen /* 298550e691bSryan_chen * According to data sheet, for 10/100 mode the MAC clock frequency 299550e691bSryan_chen * should be at least 25MHz and for 1000 mode at least 100MHz 300550e691bSryan_chen */ 301550e691bSryan_chen hwstrap = readl(priv->regs + ASPEED_STRAP); 302550e691bSryan_chen if (hwstrap & (SCU_HWSTRAP_MAC1_RGMII | SCU_HWSTRAP_MAC2_RGMII)) 303550e691bSryan_chen required_rate = 100 * 1000 * 1000; 304550e691bSryan_chen else 305550e691bSryan_chen required_rate = 25 * 1000 * 1000; 306550e691bSryan_chen 307550e691bSryan_chen divisor = hpll_rate / required_rate; 308550e691bSryan_chen 309550e691bSryan_chen if (divisor < 4) { 310550e691bSryan_chen /* Clock can't run fast enough, but let's try anyway */ 311550e691bSryan_chen debug("MAC clock too slow\n"); 312550e691bSryan_chen divisor = 4; 313550e691bSryan_chen } else if (divisor > 16) { 314550e691bSryan_chen /* Can't slow down the clock enough, but let's try anyway */ 315550e691bSryan_chen debug("MAC clock too fast\n"); 316550e691bSryan_chen divisor = 16; 317550e691bSryan_chen } 318550e691bSryan_chen 319550e691bSryan_chen switch (index) { 320550e691bSryan_chen case 1: 321550e691bSryan_chen reset_bit = SCU_SYSRESET_MAC1; 322550e691bSryan_chen clkstop_bit = SCU_CLKSTOP_MAC1; 323550e691bSryan_chen break; 324550e691bSryan_chen case 2: 325550e691bSryan_chen reset_bit = SCU_SYSRESET_MAC2; 326550e691bSryan_chen clkstop_bit = SCU_CLKSTOP_MAC2; 327550e691bSryan_chen break; 328550e691bSryan_chen default: 329550e691bSryan_chen return -EINVAL; 330550e691bSryan_chen } 331550e691bSryan_chen 332550e691bSryan_chen clrsetbits_le32(priv->regs + ASPEED_CLK_SELECT, SCU_MACCLK_MASK, 333550e691bSryan_chen ((divisor - 2) / 2) << SCU_MACCLK_SHIFT); 334550e691bSryan_chen 335550e691bSryan_chen /* 336550e691bSryan_chen * Disable MAC, start its clock and re-enable it. 337550e691bSryan_chen * The procedure and the delays (100us & 10ms) are 338550e691bSryan_chen * specified in the datasheet. 339550e691bSryan_chen */ 340550e691bSryan_chen setbits_le32(&scu->sysreset_ctrl1, reset_bit); 341550e691bSryan_chen udelay(100); 342550e691bSryan_chen clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit); 343550e691bSryan_chen mdelay(10); 344550e691bSryan_chen clrbits_le32(&scu->sysreset_ctrl1, reset_bit); 345550e691bSryan_chen 346550e691bSryan_chen writel((RGMII2_TXCK_DUTY << SCU_CLKDUTY_RGMII2TXCK_SHIFT) 347550e691bSryan_chen | (RGMII1_TXCK_DUTY << SCU_CLKDUTY_RGMII1TXCK_SHIFT), 348550e691bSryan_chen &scu->clk_duty_sel); 349550e691bSryan_chen #endif 350550e691bSryan_chen return required_rate; 351550e691bSryan_chen } 352550e691bSryan_chen 353550e691bSryan_chen static ulong aspeed_configure_d2pll(struct aspeed_clk_priv *priv, ulong rate) 354550e691bSryan_chen { 355550e691bSryan_chen /* 356550e691bSryan_chen * The values and the meaning of the next three 357550e691bSryan_chen * parameters are undocumented. Taken from Aspeed SDK. 358550e691bSryan_chen * 359550e691bSryan_chen * TODO(clg@kaod.org): the SIP and SIC values depend on the 360550e691bSryan_chen * Numerator value 361550e691bSryan_chen */ 362550e691bSryan_chen 363550e691bSryan_chen const u32 d2_pll_ext_param = 0x2c; 364550e691bSryan_chen const u32 d2_pll_sip = 0x11; 365550e691bSryan_chen const u32 d2_pll_sic = 0x18; 366550e691bSryan_chen u32 clk_delay_settings = 367550e691bSryan_chen (RMII_RXCLK_IDLY << SCU_MICDS_MAC1RMII_RDLY_SHIFT) 368550e691bSryan_chen | (RMII_RXCLK_IDLY << SCU_MICDS_MAC2RMII_RDLY_SHIFT) 369550e691bSryan_chen | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC1RGMII_TXDLY_SHIFT) 370550e691bSryan_chen | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC2RGMII_TXDLY_SHIFT); 371550e691bSryan_chen struct aspeed_div_config div_cfg = { 372550e691bSryan_chen .num = SCU_D2PLL_NUM_MASK >> SCU_D2PLL_NUM_SHIFT, 373550e691bSryan_chen .denum = SCU_D2PLL_DENUM_MASK >> SCU_D2PLL_DENUM_SHIFT, 374550e691bSryan_chen .post_div = SCU_D2PLL_POST_MASK >> SCU_D2PLL_POST_SHIFT, 375550e691bSryan_chen }; 376d6e349c7Sryan_chen ulong clkin = AST2600_CLK_IN; 377550e691bSryan_chen ulong new_rate; 378550e691bSryan_chen #if 0 379550e691bSryan_chen writel((d2_pll_ext_param << SCU_D2PLL_EXT1_PARAM_SHIFT) 380550e691bSryan_chen | SCU_D2PLL_EXT1_OFF 381550e691bSryan_chen | SCU_D2PLL_EXT1_RESET, &scu->d2_pll_ext_param[0]); 382550e691bSryan_chen 383550e691bSryan_chen /* 384550e691bSryan_chen * Select USB2.0 port1 PHY clock as a clock source for GCRT. 385550e691bSryan_chen * This would disconnect it from D2-PLL. 386550e691bSryan_chen */ 387550e691bSryan_chen clrsetbits_le32(&scu->misc_ctrl1, SCU_MISC_D2PLL_OFF, 388550e691bSryan_chen SCU_MISC_GCRT_USB20CLK); 389550e691bSryan_chen 390550e691bSryan_chen new_rate = aspeed_calc_clock_config(clkin, rate, &div_cfg); 391550e691bSryan_chen writel((d2_pll_sip << SCU_D2PLL_SIP_SHIFT) 392550e691bSryan_chen | (d2_pll_sic << SCU_D2PLL_SIC_SHIFT) 393550e691bSryan_chen | (div_cfg.num << SCU_D2PLL_NUM_SHIFT) 394550e691bSryan_chen | (div_cfg.denum << SCU_D2PLL_DENUM_SHIFT) 395550e691bSryan_chen | (div_cfg.post_div << SCU_D2PLL_POST_SHIFT), 396550e691bSryan_chen &scu->d2_pll_param); 397550e691bSryan_chen 398550e691bSryan_chen clrbits_le32(&scu->d2_pll_ext_param[0], 399550e691bSryan_chen SCU_D2PLL_EXT1_OFF | SCU_D2PLL_EXT1_RESET); 400550e691bSryan_chen 401550e691bSryan_chen clrsetbits_le32(&scu->misc_ctrl2, 402550e691bSryan_chen SCU_MISC2_RGMII_HPLL | SCU_MISC2_RMII_MPLL 403550e691bSryan_chen | SCU_MISC2_RGMII_CLKDIV_MASK | 404550e691bSryan_chen SCU_MISC2_RMII_CLKDIV_MASK, 405550e691bSryan_chen (4 << SCU_MISC2_RMII_CLKDIV_SHIFT)); 406550e691bSryan_chen 407550e691bSryan_chen writel(clk_delay_settings | SCU_MICDS_RGMIIPLL, &scu->mac_clk_delay); 408550e691bSryan_chen writel(clk_delay_settings, &scu->mac_clk_delay_100M); 409550e691bSryan_chen writel(clk_delay_settings, &scu->mac_clk_delay_10M); 410550e691bSryan_chen #endif 411550e691bSryan_chen return new_rate; 412550e691bSryan_chen } 413550e691bSryan_chen 414d6e349c7Sryan_chen static ulong ast2600_clk_get_rate(struct clk *clk) 415d6e349c7Sryan_chen { 416d6e349c7Sryan_chen struct aspeed_clk_priv *priv = dev_get_priv(clk->dev); 417d6e349c7Sryan_chen ulong rate; 418d6e349c7Sryan_chen 419d6e349c7Sryan_chen switch (clk->id) { 420d1e64dd1Sryan_chen //HPLL 421d1e64dd1Sryan_chen case ASPEED_CLK_HPLL: 422*62a6bcbfSryan_chen rate = ast2600_get_hpll_rate(priv); 423d6e349c7Sryan_chen break; 424d1e64dd1Sryan_chen //HCLK 425d1e64dd1Sryan_chen case ASPEED_CLK_AHB: 426*62a6bcbfSryan_chen { 427*62a6bcbfSryan_chen ulong ahb_div = 1 + ((readl(&priv->scu->hwstrap) 428*62a6bcbfSryan_chen & SCU_HWSTRAP_AXIAHB_DIV_MASK) 429*62a6bcbfSryan_chen >> SCU_HWSTRAP_AXIAHB_DIV_SHIFT); 430*62a6bcbfSryan_chen ulong axi_div = 2; 431*62a6bcbfSryan_chen 432*62a6bcbfSryan_chen rate = ast2600_get_hpll_rate( 433*62a6bcbfSryan_chen clkin, readl(&priv->scu->h_pll_param)); 434*62a6bcbfSryan_chen rate = rate / axi_div / ahb_div; 435*62a6bcbfSryan_chen } 436d1e64dd1Sryan_chen break; 437d1e64dd1Sryan_chen 438d6e349c7Sryan_chen case MCLK_DDR: 439d6e349c7Sryan_chen rate = aspeed_get_mpll_rate(priv); 440d6e349c7Sryan_chen break; 441d6e349c7Sryan_chen case BCLK_PCLK: 442d6e349c7Sryan_chen { 443d6e349c7Sryan_chen ulong apb_div = 4 + 4 * ((readl(priv->regs + ASPEED_CLK_SELECT) 444d6e349c7Sryan_chen & SCU_PCLK_DIV_MASK) 445d6e349c7Sryan_chen >> SCU_PCLK_DIV_SHIFT); 446*62a6bcbfSryan_chen rate = ast2600_get_hpll_rate(priv); 447d6e349c7Sryan_chen rate = rate / apb_div; 448d6e349c7Sryan_chen } 449d6e349c7Sryan_chen break; 450d6e349c7Sryan_chen case PCLK_UART1: 451d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 1); 452d6e349c7Sryan_chen break; 453d6e349c7Sryan_chen case PCLK_UART2: 454d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 2); 455d6e349c7Sryan_chen break; 456d6e349c7Sryan_chen case PCLK_UART3: 457d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 3); 458d6e349c7Sryan_chen break; 459d6e349c7Sryan_chen case PCLK_UART4: 460d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 4); 461d6e349c7Sryan_chen break; 462d1e64dd1Sryan_chen case ASPEED_CLK_GATE_UART5CLK: 463d6e349c7Sryan_chen rate = ast2600_get_uart_clk_rate(priv, 5); 464d6e349c7Sryan_chen break; 465d6e349c7Sryan_chen default: 466d6e349c7Sryan_chen return -ENOENT; 467d6e349c7Sryan_chen } 468d6e349c7Sryan_chen 469d6e349c7Sryan_chen return rate; 470d6e349c7Sryan_chen } 471d6e349c7Sryan_chen 472d6e349c7Sryan_chen static ulong ast2600_clk_set_rate(struct clk *clk, ulong rate) 473550e691bSryan_chen { 474550e691bSryan_chen struct aspeed_clk_priv *priv = dev_get_priv(clk->dev); 475550e691bSryan_chen 476550e691bSryan_chen ulong new_rate; 477550e691bSryan_chen switch (clk->id) { 478550e691bSryan_chen case PLL_MPLL: 479550e691bSryan_chen case MCLK_DDR: 480550e691bSryan_chen new_rate = aspeed_configure_ddr(priv, rate); 481550e691bSryan_chen break; 482550e691bSryan_chen case PLL_D2PLL: 483550e691bSryan_chen new_rate = aspeed_configure_d2pll(priv, rate); 484550e691bSryan_chen break; 485550e691bSryan_chen default: 486550e691bSryan_chen return -ENOENT; 487550e691bSryan_chen } 488550e691bSryan_chen 489550e691bSryan_chen return new_rate; 490550e691bSryan_chen } 491550e691bSryan_chen 492d6e349c7Sryan_chen static int ast2600_clk_enable(struct clk *clk) 493550e691bSryan_chen { 494550e691bSryan_chen struct aspeed_clk_priv *priv = dev_get_priv(clk->dev); 495550e691bSryan_chen 496550e691bSryan_chen switch (clk->id) { 497550e691bSryan_chen /* 498550e691bSryan_chen * For MAC clocks the clock rate is 499550e691bSryan_chen * configured based on whether RGMII or RMII mode has been selected 500550e691bSryan_chen * through hardware strapping. 501550e691bSryan_chen */ 502550e691bSryan_chen case PCLK_MAC1: 503550e691bSryan_chen aspeed_configure_mac(priv, 1); 504550e691bSryan_chen break; 505550e691bSryan_chen case PCLK_MAC2: 506550e691bSryan_chen aspeed_configure_mac(priv, 2); 507550e691bSryan_chen break; 508550e691bSryan_chen case PLL_D2PLL: 509550e691bSryan_chen aspeed_configure_d2pll(priv, D2PLL_DEFAULT_RATE); 510550e691bSryan_chen break; 511550e691bSryan_chen default: 512550e691bSryan_chen return -ENOENT; 513550e691bSryan_chen } 514550e691bSryan_chen 515550e691bSryan_chen return 0; 516550e691bSryan_chen } 517550e691bSryan_chen 518550e691bSryan_chen struct clk_ops aspeed_clk_ops = { 519d6e349c7Sryan_chen .get_rate = ast2600_clk_get_rate, 520d6e349c7Sryan_chen .set_rate = ast2600_clk_set_rate, 521d6e349c7Sryan_chen .enable = ast2600_clk_enable, 522550e691bSryan_chen }; 523550e691bSryan_chen 524d6e349c7Sryan_chen static int ast2600_clk_probe(struct udevice *dev) 525550e691bSryan_chen { 526550e691bSryan_chen struct aspeed_clk_priv *priv = dev_get_priv(dev); 527550e691bSryan_chen 528550e691bSryan_chen priv->regs = devfdt_get_addr_ptr(dev); 529550e691bSryan_chen 530550e691bSryan_chen if (IS_ERR(priv->regs)) 531550e691bSryan_chen return PTR_ERR(priv->regs); 532550e691bSryan_chen 533550e691bSryan_chen priv->version = dev_get_driver_data(dev); 534550e691bSryan_chen 535550e691bSryan_chen return 0; 536550e691bSryan_chen } 537550e691bSryan_chen 538d6e349c7Sryan_chen static int ast2600_clk_bind(struct udevice *dev) 539550e691bSryan_chen { 540550e691bSryan_chen int ret; 541550e691bSryan_chen 542550e691bSryan_chen /* The reset driver does not have a device node, so bind it here */ 543550e691bSryan_chen ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev); 544550e691bSryan_chen if (ret) 545550e691bSryan_chen debug("Warning: No reset driver: ret=%d\n", ret); 546550e691bSryan_chen 547550e691bSryan_chen return 0; 548550e691bSryan_chen } 549550e691bSryan_chen 550d6e349c7Sryan_chen static const struct udevice_id ast2600_clk_ids[] = { 551d6e349c7Sryan_chen { .compatible = "aspeed,ast2600-scu", }, 552550e691bSryan_chen { } 553550e691bSryan_chen }; 554550e691bSryan_chen 555aa36597fSDylan Hung U_BOOT_DRIVER(aspeed_scu) = { 556aa36597fSDylan Hung .name = "aspeed_scu", 557550e691bSryan_chen .id = UCLASS_CLK, 558d6e349c7Sryan_chen .of_match = ast2600_clk_ids, 559550e691bSryan_chen .priv_auto_alloc_size = sizeof(struct aspeed_clk_priv), 560550e691bSryan_chen .ops = &aspeed_clk_ops, 561d6e349c7Sryan_chen .bind = ast2600_clk_bind, 562d6e349c7Sryan_chen .probe = ast2600_clk_probe, 563550e691bSryan_chen }; 564