1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) ASPEED Technology Inc. 4 * Ryan Chen <ryan_chen@aspeedtech.com> 5 */ 6 7 #include <common.h> 8 #include <clk-uclass.h> 9 #include <dm.h> 10 #include <asm/io.h> 11 #include <dm/lists.h> 12 #include <asm/arch/scu_ast2600.h> 13 #include <dt-bindings/clock/ast2600-clock.h> 14 #include <dt-bindings/reset/ast2600-reset.h> 15 16 /* 17 * MAC Clock Delay settings, taken from Aspeed SDK 18 */ 19 #define RGMII_TXCLK_ODLY 8 20 #define RMII_RXCLK_IDLY 2 21 22 /* 23 * TGMII Clock Duty constants, taken from Aspeed SDK 24 */ 25 #define RGMII2_TXCK_DUTY 0x66 26 #define RGMII1_TXCK_DUTY 0x64 27 28 #define D2PLL_DEFAULT_RATE (250 * 1000 * 1000) 29 30 DECLARE_GLOBAL_DATA_PTR; 31 32 /* 33 * Clock divider/multiplier configuration struct. 34 * For H-PLL and M-PLL the formula is 35 * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1) 36 * M - Numerator 37 * N - Denumerator 38 * P - Post Divider 39 * They have the same layout in their control register. 40 * 41 * D-PLL and D2-PLL have extra divider (OD + 1), which is not 42 * yet needed and ignored by clock configurations. 43 */ 44 struct ast2600_div_config { 45 unsigned int num; 46 unsigned int denum; 47 unsigned int post_div; 48 }; 49 50 #define AST2600_CLK_IN 25000000 51 52 /* 53 * Get the rate of the M-PLL clock from input clock frequency and 54 * the value of the M-PLL Parameter Register. 55 */ 56 static u32 ast2600_get_mpll_rate(struct ast2600_scu *scu) 57 { 58 u32 clkin = AST2600_CLK_IN; 59 u32 mpll_reg = readl(&scu->m_pll_param); 60 61 printf("&scu->m_pll_param %x \n", (u32) &scu->m_pll_param); 62 const ulong num = mpll_reg & 0x1fff; 63 const ulong denum = (mpll_reg >> 13) & 0x3f; 64 const ulong post_div = (mpll_reg >> 19) & 0xf; 65 66 return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1); 67 } 68 69 /* 70 * Get the rate of the H-PLL clock from input clock frequency and 71 * the value of the H-PLL Parameter Register. 72 */ 73 static ulong ast2600_get_hpll_rate(struct ast2600_scu *scu) 74 { 75 ulong clkin = AST2600_CLK_IN; 76 u32 hpll_reg = readl(&scu->h_pll_param); 77 78 printf("&scu->h_pll_param %x \n", (u32) &scu->h_pll_param); 79 80 const ulong num = (hpll_reg & 0x1fff); 81 const ulong denum = (hpll_reg >> 13) & 0x3f; 82 const ulong post_div = (hpll_reg >> 19) & 0xf; 83 84 return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1); 85 } 86 87 static ulong ast2600_get_apll_rate(struct ast2600_scu *scu) 88 { 89 u32 clk_in = AST2600_CLK_IN; 90 u32 apll_reg = readl(&scu->a_pll_param); 91 unsigned int mult, div = 1; 92 93 printf("&scu->h_pll_param %x \n", (u32) &scu->a_pll_param); 94 95 if (apll_reg & BIT(20)) { 96 /* Pass through mode */ 97 mult = div = 1; 98 } else { 99 /* F = 25Mhz * (2-OD) * [(M + 2) / (n + 1)] */ 100 u32 m = (apll_reg >> 5) & 0x3f; 101 u32 od = (apll_reg >> 4) & 0x1; 102 u32 n = apll_reg & 0xf; 103 104 mult = (2 - od) * ((m + 2) / (n + 1)); 105 } 106 return (clk_in * mult)/div; 107 } 108 109 static ulong ast2600_get_epll_rate(struct ast2600_scu *scu) 110 { 111 u32 clk_in = AST2600_CLK_IN; 112 u32 epll_reg = readl(&scu->e_pll_param); 113 unsigned int mult, div = 1; 114 115 printf("&scu->e_pll_param %x \n", (u32) &scu->e_pll_param); 116 117 if (epll_reg & BIT(24)) { 118 /* Pass through mode */ 119 mult = div = 1; 120 } else { 121 /* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1)*/ 122 u32 m = epll_reg & 0x1fff; 123 u32 n = (epll_reg >> 13) & 0x3f; 124 u32 p = (epll_reg >> 19) & 0x7; 125 126 mult = ((m + 1) / (n + 1)); 127 div = (p + 1); 128 } 129 return (clk_in * mult)/div; 130 } 131 132 static ulong ast2600_get_dpll_rate(struct ast2600_scu *scu) 133 { 134 u32 clk_in = AST2600_CLK_IN; 135 u32 dpll_reg = readl(&scu->d_pll_param); 136 unsigned int mult, div = 1; 137 138 printf("&scu->d_pll_param %x \n", (u32) &scu->d_pll_param); 139 140 if (dpll_reg & BIT(24)) { 141 /* Pass through mode */ 142 mult = div = 1; 143 } else { 144 /* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1)*/ 145 u32 m = dpll_reg & 0x1fff; 146 u32 n = (dpll_reg >> 13) & 0x3f; 147 u32 p = (dpll_reg >> 19) & 0x7; 148 149 mult = ((m + 1) / (n + 1)); 150 div = (p + 1); 151 } 152 return (clk_in * mult)/div; 153 } 154 155 static ulong ast2600_get_uart_clk_rate(struct ast2600_clk_priv *priv, int uart_index) 156 { 157 ulong uart_clkin; 158 159 printf("ast2600_get_uart_clk_rate source %ld \n\n", ast2600_get_apll_rate(priv->scu)); 160 return (24000000/13); 161 162 if (readl(&priv->scu->misc_ctrl2) & 163 (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT))) 164 uart_clkin = 192 * 1000 * 1000; 165 else 166 uart_clkin = 24 * 1000 * 1000; 167 168 if (readl(&priv->scu->misc_ctrl2) & SCU_MISC_UARTCLK_DIV13) 169 uart_clkin /= 13; 170 171 return uart_clkin; 172 } 173 174 struct aspeed_clock_config { 175 ulong input_rate; 176 ulong rate; 177 struct ast2600_div_config cfg; 178 }; 179 180 static const struct aspeed_clock_config aspeed_clock_config_defaults[] = { 181 { 25000000, 400000000, { .num = 95, .denum = 2, .post_div = 1 } }, 182 }; 183 184 static bool aspeed_get_clock_config_default(ulong input_rate, 185 ulong requested_rate, 186 struct ast2600_div_config *cfg) 187 { 188 int i; 189 190 for (i = 0; i < ARRAY_SIZE(aspeed_clock_config_defaults); i++) { 191 const struct aspeed_clock_config *default_cfg = 192 &aspeed_clock_config_defaults[i]; 193 if (default_cfg->input_rate == input_rate && 194 default_cfg->rate == requested_rate) { 195 *cfg = default_cfg->cfg; 196 return true; 197 } 198 } 199 200 return false; 201 } 202 203 /* 204 * @input_rate - the rate of input clock in Hz 205 * @requested_rate - desired output rate in Hz 206 * @div - this is an IN/OUT parameter, at input all fields of the config 207 * need to be set to their maximum allowed values. 208 * The result (the best config we could find), would also be returned 209 * in this structure. 210 * 211 * @return The clock rate, when the resulting div_config is used. 212 */ 213 static ulong aspeed_calc_clock_config(ulong input_rate, ulong requested_rate, 214 struct ast2600_div_config *cfg) 215 { 216 /* 217 * The assumption is that kHz precision is good enough and 218 * also enough to avoid overflow when multiplying. 219 */ 220 const ulong input_rate_khz = input_rate / 1000; 221 const ulong rate_khz = requested_rate / 1000; 222 const struct ast2600_div_config max_vals = *cfg; 223 struct ast2600_div_config it = { 0, 0, 0 }; 224 ulong delta = rate_khz; 225 ulong new_rate_khz = 0; 226 227 /* 228 * Look for a well known frequency first. 229 */ 230 if (aspeed_get_clock_config_default(input_rate, requested_rate, cfg)) 231 return requested_rate; 232 233 for (; it.denum <= max_vals.denum; ++it.denum) { 234 for (it.post_div = 0; it.post_div <= max_vals.post_div; 235 ++it.post_div) { 236 it.num = (rate_khz * (it.post_div + 1) / input_rate_khz) 237 * (it.denum + 1); 238 if (it.num > max_vals.num) 239 continue; 240 241 new_rate_khz = (input_rate_khz 242 * ((it.num + 1) / (it.denum + 1))) 243 / (it.post_div + 1); 244 245 /* Keep the rate below requested one. */ 246 if (new_rate_khz > rate_khz) 247 continue; 248 249 if (new_rate_khz - rate_khz < delta) { 250 delta = new_rate_khz - rate_khz; 251 *cfg = it; 252 if (delta == 0) 253 return new_rate_khz * 1000; 254 } 255 } 256 } 257 258 return new_rate_khz * 1000; 259 } 260 261 static u32 ast2600_configure_ddr(struct ast2600_clk_priv *priv, ulong rate) 262 { 263 u32 clkin = AST2600_CLK_IN; 264 u32 mpll_reg; 265 struct ast2600_div_config div_cfg = { 266 .num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT), 267 .denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT), 268 .post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT), 269 }; 270 271 aspeed_calc_clock_config(clkin, rate, &div_cfg); 272 273 mpll_reg = readl(&priv->scu->m_pll_param); 274 mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK 275 | SCU_MPLL_DENUM_MASK); 276 mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT) 277 | (div_cfg.num << SCU_MPLL_NUM_SHIFT) 278 | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT); 279 280 writel(mpll_reg, &priv->scu->m_pll_param); 281 282 return ast2600_get_mpll_rate(priv->scu); 283 } 284 285 static u32 ast2600_configure_mac(struct ast2600_clk_priv *priv, int index) 286 { 287 return 0; 288 } 289 290 static u32 ast2600_a0_axi_ahb_div_table[] = { 291 2, 2, 3, 5, 292 }; 293 294 static u32 ast2600_a1_axi_ahb_div_table[] = { 295 4, 6, 2, 4, 296 }; 297 298 static u32 ast2600_hpll_pclk_div_table[] = { 299 4, 8, 12, 16, 20, 24, 28, 32, 300 }; 301 static ulong ast2600_clk_get_rate(struct clk *clk) 302 { 303 struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 304 ulong rate; 305 306 switch (clk->id) { 307 //HPLL 308 case ASPEED_CLK_HPLL: 309 rate = ast2600_get_hpll_rate(priv->scu); 310 printf("hpll %ld \n", rate); 311 break; 312 //HCLK 313 case ASPEED_CLK_AHB: 314 { 315 u32 hw_rev = readl(&priv->scu->chip_id0); 316 u32 hwstrap1 = readl(&priv->scu->hwstrap1); 317 u32 axi_div = 1; 318 u32 ahb_div = 0; 319 if((hwstrap1 >> 16) & 0x1) 320 axi_div = 1; 321 else 322 axi_div = 2; 323 324 if (hw_rev & BIT(16)) 325 ahb_div = ast2600_a1_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 326 else 327 ahb_div = ast2600_a0_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 328 329 rate = ast2600_get_hpll_rate(priv->scu); 330 rate = rate / axi_div / ahb_div; 331 } 332 break; 333 case ASPEED_CLK_MPLL: 334 rate = ast2600_get_mpll_rate(priv->scu); 335 break; 336 //pclk 337 case ASPEED_CLK_APB: 338 { 339 u32 clk_sel1 = readl(&priv->scu->clk_sel1); 340 u32 apb_div = ast2600_hpll_pclk_div_table[((clk_sel1 >> 23) & 0x7)]; 341 rate = ast2600_get_hpll_rate(priv->scu); 342 rate = rate / apb_div; 343 } 344 break; 345 case PCLK_UART1: 346 rate = ast2600_get_uart_clk_rate(priv, 1); 347 break; 348 case PCLK_UART2: 349 rate = ast2600_get_uart_clk_rate(priv, 2); 350 break; 351 case PCLK_UART3: 352 rate = ast2600_get_uart_clk_rate(priv, 3); 353 break; 354 case PCLK_UART4: 355 rate = ast2600_get_uart_clk_rate(priv, 4); 356 break; 357 case ASPEED_CLK_GATE_UART5CLK: 358 rate = ast2600_get_uart_clk_rate(priv, 5); 359 break; 360 default: 361 return -ENOENT; 362 } 363 364 return rate; 365 } 366 367 static ulong ast2600_clk_set_rate(struct clk *clk, ulong rate) 368 { 369 struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 370 371 ulong new_rate; 372 switch (clk->id) { 373 case ASPEED_CLK_MPLL: 374 new_rate = ast2600_configure_ddr(priv, rate); 375 break; 376 default: 377 return -ENOENT; 378 } 379 380 return new_rate; 381 } 382 383 static int ast2600_clk_enable(struct clk *clk) 384 { 385 struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 386 387 switch (clk->id) { 388 /* 389 * For MAC clocks the clock rate is 390 * configured based on whether RGMII or RMII mode has been selected 391 * through hardware strapping. 392 */ 393 case PCLK_MAC1: 394 ast2600_configure_mac(priv, 1); 395 break; 396 case PCLK_MAC2: 397 ast2600_configure_mac(priv, 2); 398 break; 399 default: 400 return -ENOENT; 401 } 402 403 return 0; 404 } 405 406 struct clk_ops aspeed_clk_ops = { 407 .get_rate = ast2600_clk_get_rate, 408 .set_rate = ast2600_clk_set_rate, 409 .enable = ast2600_clk_enable, 410 }; 411 412 static int ast2600_clk_probe(struct udevice *dev) 413 { 414 char buf[32]; 415 struct ast2600_clk_priv *priv = dev_get_priv(dev); 416 417 priv->scu = devfdt_get_addr_ptr(dev); 418 if (IS_ERR(priv->scu)) 419 return PTR_ERR(priv->scu); 420 421 printf("PLL : %4s MHz\n", strmhz(buf, AST2600_CLK_IN)); 422 printf("HPLL : %4s MHz\n", strmhz(buf, ast2600_get_hpll_rate(priv->scu))); 423 printf("MPLL : %4s Mhz\n", strmhz(buf, ast2600_get_mpll_rate(priv->scu))); 424 printf("APLL : %4s Mhz\n", strmhz(buf, ast2600_get_apll_rate(priv->scu))); 425 printf("EPLL : %4s Mhz\n", strmhz(buf, ast2600_get_epll_rate(priv->scu))); 426 printf("DPLL : %4s Mhz\n", strmhz(buf, ast2600_get_dpll_rate(priv->scu))); 427 428 429 return 0; 430 } 431 432 static int ast2600_clk_bind(struct udevice *dev) 433 { 434 int ret; 435 436 /* The reset driver does not have a device node, so bind it here */ 437 ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev); 438 if (ret) 439 debug("Warning: No reset driver: ret=%d\n", ret); 440 441 return 0; 442 } 443 444 static const struct udevice_id ast2600_clk_ids[] = { 445 { .compatible = "aspeed,ast2600-scu", }, 446 { } 447 }; 448 449 U_BOOT_DRIVER(aspeed_scu) = { 450 .name = "aspeed_scu", 451 .id = UCLASS_CLK, 452 .of_match = ast2600_clk_ids, 453 .priv_auto_alloc_size = sizeof(struct ast2600_clk_priv), 454 .ops = &aspeed_clk_ops, 455 .bind = ast2600_clk_bind, 456 .probe = ast2600_clk_probe, 457 }; 458