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> 1439283ea7Sryan_chen #include <dt-bindings/reset/ast2600-reset.h> 15550e691bSryan_chen 16550e691bSryan_chen /* 17550e691bSryan_chen * MAC Clock Delay settings, taken from Aspeed SDK 18550e691bSryan_chen */ 19550e691bSryan_chen #define RGMII_TXCLK_ODLY 8 20550e691bSryan_chen #define RMII_RXCLK_IDLY 2 21550e691bSryan_chen 22550e691bSryan_chen /* 23550e691bSryan_chen * TGMII Clock Duty constants, taken from Aspeed SDK 24550e691bSryan_chen */ 25550e691bSryan_chen #define RGMII2_TXCK_DUTY 0x66 26550e691bSryan_chen #define RGMII1_TXCK_DUTY 0x64 27550e691bSryan_chen 28550e691bSryan_chen #define D2PLL_DEFAULT_RATE (250 * 1000 * 1000) 29550e691bSryan_chen 30550e691bSryan_chen DECLARE_GLOBAL_DATA_PTR; 31550e691bSryan_chen 32550e691bSryan_chen /* 33550e691bSryan_chen * Clock divider/multiplier configuration struct. 34550e691bSryan_chen * For H-PLL and M-PLL the formula is 35550e691bSryan_chen * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1) 36550e691bSryan_chen * M - Numerator 37550e691bSryan_chen * N - Denumerator 38550e691bSryan_chen * P - Post Divider 39550e691bSryan_chen * They have the same layout in their control register. 40550e691bSryan_chen * 41550e691bSryan_chen * D-PLL and D2-PLL have extra divider (OD + 1), which is not 42550e691bSryan_chen * yet needed and ignored by clock configurations. 43550e691bSryan_chen */ 4439283ea7Sryan_chen struct ast2600_div_config { 45550e691bSryan_chen unsigned int num; 46550e691bSryan_chen unsigned int denum; 47550e691bSryan_chen unsigned int post_div; 48550e691bSryan_chen }; 49550e691bSryan_chen 50*bbbfb0c5Sryan_chen extern u32 ast2600_get_pll_rate(struct ast2600_scu *scu, int pll_idx) 51550e691bSryan_chen { 52d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 53*bbbfb0c5Sryan_chen u32 pll_reg = 0; 549639db61Sryan_chen unsigned int mult, div = 1; 55550e691bSryan_chen 56*bbbfb0c5Sryan_chen switch(pll_idx) { 57*bbbfb0c5Sryan_chen case ASPEED_CLK_HPLL: 58*bbbfb0c5Sryan_chen pll_reg = readl(&scu->h_pll_param); 59*bbbfb0c5Sryan_chen break; 60*bbbfb0c5Sryan_chen case ASPEED_CLK_MPLL: 61*bbbfb0c5Sryan_chen pll_reg = readl(&scu->m_pll_param); 62*bbbfb0c5Sryan_chen break; 63*bbbfb0c5Sryan_chen case ASPEED_CLK_DPLL: 64*bbbfb0c5Sryan_chen pll_reg = readl(&scu->d_pll_param); 65*bbbfb0c5Sryan_chen break; 66*bbbfb0c5Sryan_chen case ASPEED_CLK_EPLL: 67*bbbfb0c5Sryan_chen pll_reg = readl(&scu->e_pll_param); 68*bbbfb0c5Sryan_chen break; 69*bbbfb0c5Sryan_chen 70*bbbfb0c5Sryan_chen } 71*bbbfb0c5Sryan_chen if (pll_reg & BIT(24)) { 729639db61Sryan_chen /* Pass through mode */ 739639db61Sryan_chen mult = div = 1; 749639db61Sryan_chen } else { 759639db61Sryan_chen /* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1) */ 76*bbbfb0c5Sryan_chen u32 m = pll_reg & 0x1fff; 77*bbbfb0c5Sryan_chen u32 n = (pll_reg >> 13) & 0x3f; 78*bbbfb0c5Sryan_chen u32 p = (pll_reg >> 19) & 0xf; 799639db61Sryan_chen mult = (m + 1) / (n + 1); 809639db61Sryan_chen div = (p + 1); 819639db61Sryan_chen } 829639db61Sryan_chen return ((clkin * mult)/div); 83550e691bSryan_chen 84550e691bSryan_chen } 85550e691bSryan_chen 864f22e838Sryan_chen extern u32 ast2600_get_apll_rate(struct ast2600_scu *scu) 87550e691bSryan_chen { 88*bbbfb0c5Sryan_chen u32 clkin = AST2600_CLK_IN; 8939283ea7Sryan_chen u32 apll_reg = readl(&scu->a_pll_param); 9039283ea7Sryan_chen unsigned int mult, div = 1; 91d6e349c7Sryan_chen 9239283ea7Sryan_chen if (apll_reg & BIT(20)) { 93d6e349c7Sryan_chen /* Pass through mode */ 94d6e349c7Sryan_chen mult = div = 1; 95d6e349c7Sryan_chen } else { 96*bbbfb0c5Sryan_chen /* F = 25Mhz * (2-od) * [(m + 2) / (n + 1)] */ 9739283ea7Sryan_chen u32 m = (apll_reg >> 5) & 0x3f; 9839283ea7Sryan_chen u32 od = (apll_reg >> 4) & 0x1; 9939283ea7Sryan_chen u32 n = apll_reg & 0xf; 100d6e349c7Sryan_chen 101*bbbfb0c5Sryan_chen mult = (2 - od) * (m + 2); 102*bbbfb0c5Sryan_chen div = n + 1; 103d6e349c7Sryan_chen } 104*bbbfb0c5Sryan_chen return ((clkin * mult)/div); 10539283ea7Sryan_chen } 10639283ea7Sryan_chen 107d812df15Sryan_chen static u32 ast2600_a0_axi_ahb_div_table[] = { 108d812df15Sryan_chen 2, 2, 3, 5, 109d812df15Sryan_chen }; 110d812df15Sryan_chen 111d812df15Sryan_chen static u32 ast2600_a1_axi_ahb_div_table[] = { 112d812df15Sryan_chen 4, 6, 2, 4, 113d812df15Sryan_chen }; 114d812df15Sryan_chen 115d812df15Sryan_chen static u32 ast2600_get_hclk(struct ast2600_scu *scu) 116d812df15Sryan_chen { 117d812df15Sryan_chen u32 hw_rev = readl(&scu->chip_id0); 118d812df15Sryan_chen u32 hwstrap1 = readl(&scu->hwstrap1); 119d812df15Sryan_chen u32 axi_div = 1; 120d812df15Sryan_chen u32 ahb_div = 0; 121d812df15Sryan_chen u32 rate = 0; 122d812df15Sryan_chen 123d812df15Sryan_chen if((hwstrap1 >> 16) & 0x1) 124d812df15Sryan_chen axi_div = 1; 125d812df15Sryan_chen else 126d812df15Sryan_chen axi_div = 2; 127d812df15Sryan_chen 128d812df15Sryan_chen if (hw_rev & BIT(16)) 129d812df15Sryan_chen ahb_div = ast2600_a1_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 130d812df15Sryan_chen else 131d812df15Sryan_chen ahb_div = ast2600_a0_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 132d812df15Sryan_chen 133*bbbfb0c5Sryan_chen rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL); 134d812df15Sryan_chen 1352717883aSryan_chen return (rate / axi_div / ahb_div); 1362717883aSryan_chen } 1372717883aSryan_chen 1382717883aSryan_chen static u32 ast2600_hpll_pclk_div_table[] = { 1392717883aSryan_chen 4, 8, 12, 16, 20, 24, 28, 32, 1402717883aSryan_chen }; 1412717883aSryan_chen 1422717883aSryan_chen static u32 ast2600_get_pclk(struct ast2600_scu *scu) 1432717883aSryan_chen { 1442717883aSryan_chen u32 clk_sel1 = readl(&scu->clk_sel1); 1452717883aSryan_chen u32 apb_div = ast2600_hpll_pclk_div_table[((clk_sel1 >> 23) & 0x7)]; 146*bbbfb0c5Sryan_chen u32 rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL); 1472717883aSryan_chen 1482717883aSryan_chen return (rate / apb_div); 149d812df15Sryan_chen } 150d812df15Sryan_chen 151d6e349c7Sryan_chen 15227881d20Sryan_chen static u32 ast2600_get_uxclk_rate(struct ast2600_scu *scu) 153d6e349c7Sryan_chen { 15427881d20Sryan_chen u32 clk_in = 0; 15527881d20Sryan_chen u32 uxclk_sel = readl(&scu->clk_sel4); 156550e691bSryan_chen 15727881d20Sryan_chen uxclk_sel &= 0x3; 15827881d20Sryan_chen switch(uxclk_sel) { 15927881d20Sryan_chen case 0: 16027881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 4; 16127881d20Sryan_chen break; 16227881d20Sryan_chen case 1: 16327881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 2; 16427881d20Sryan_chen break; 16527881d20Sryan_chen case 2: 16627881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu); 16727881d20Sryan_chen break; 16827881d20Sryan_chen case 3: 16927881d20Sryan_chen clk_in = ast2600_get_hclk(scu); 17027881d20Sryan_chen break; 17127881d20Sryan_chen } 172d6e349c7Sryan_chen 17327881d20Sryan_chen return clk_in; 17427881d20Sryan_chen } 17527881d20Sryan_chen 17627881d20Sryan_chen static u32 ast2600_get_huxclk_rate(struct ast2600_scu *scu) 17727881d20Sryan_chen { 17827881d20Sryan_chen u32 clk_in = 0; 17927881d20Sryan_chen u32 huclk_sel = readl(&scu->clk_sel4); 18027881d20Sryan_chen 18127881d20Sryan_chen huclk_sel = ((huclk_sel >> 3) & 0x3); 18227881d20Sryan_chen switch(huclk_sel) { 18327881d20Sryan_chen case 0: 18427881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 4; 18527881d20Sryan_chen break; 18627881d20Sryan_chen case 1: 18727881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 2; 18827881d20Sryan_chen break; 18927881d20Sryan_chen case 2: 19027881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu); 19127881d20Sryan_chen break; 19227881d20Sryan_chen case 3: 19327881d20Sryan_chen clk_in = ast2600_get_hclk(scu); 19427881d20Sryan_chen break; 19527881d20Sryan_chen } 19627881d20Sryan_chen 19727881d20Sryan_chen return clk_in; 19827881d20Sryan_chen } 19927881d20Sryan_chen 20027881d20Sryan_chen static u32 ast2600_get_uart_from_uxclk_rate(struct ast2600_scu *scu) 20127881d20Sryan_chen { 20227881d20Sryan_chen u32 clk_in = ast2600_get_uxclk_rate(scu); 20327881d20Sryan_chen u32 div_reg = readl(&scu->uart_24m_ref_uxclk); 20427881d20Sryan_chen unsigned int mult, div; 20527881d20Sryan_chen 20627881d20Sryan_chen u32 n = (div_reg >> 8) & 0x3ff; 20727881d20Sryan_chen u32 r = div_reg & 0xff; 20827881d20Sryan_chen 20927881d20Sryan_chen mult = r; 21027881d20Sryan_chen div = (n * 4); 21127881d20Sryan_chen return (clk_in * mult)/div; 21227881d20Sryan_chen } 21327881d20Sryan_chen 21427881d20Sryan_chen static u32 ast2600_get_uart_from_huxclk_rate(struct ast2600_scu *scu) 21527881d20Sryan_chen { 21627881d20Sryan_chen u32 clk_in = ast2600_get_huxclk_rate(scu); 21727881d20Sryan_chen u32 div_reg = readl(&scu->uart_24m_ref_huxclk); 21827881d20Sryan_chen 21927881d20Sryan_chen unsigned int mult, div; 22027881d20Sryan_chen 22127881d20Sryan_chen u32 n = (div_reg >> 8) & 0x3ff; 22227881d20Sryan_chen u32 r = div_reg & 0xff; 22327881d20Sryan_chen 22427881d20Sryan_chen mult = r; 22527881d20Sryan_chen div = (n * 4); 22627881d20Sryan_chen return (clk_in * mult)/div; 22727881d20Sryan_chen } 22827881d20Sryan_chen 229f51926eeSryan_chen static u32 ast2600_get_sdio_clk_rate(struct ast2600_scu *scu) 230f51926eeSryan_chen { 231f51926eeSryan_chen u32 clkin = 0; 232f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel4); 233f51926eeSryan_chen u32 div = (clk_sel >> 28) & 0x7; 234f51926eeSryan_chen 235f51926eeSryan_chen if(clk_sel & BIT(8)) { 236f51926eeSryan_chen clkin = ast2600_get_apll_rate(scu); 237f51926eeSryan_chen } else { 238f51926eeSryan_chen clkin = 200 * 1000 * 1000; 239f51926eeSryan_chen } 240f51926eeSryan_chen div = (div + 1) << 1; 241f51926eeSryan_chen 242f51926eeSryan_chen return (clkin / div); 243f51926eeSryan_chen } 244f51926eeSryan_chen 245f51926eeSryan_chen static u32 ast2600_get_emmc_clk_rate(struct ast2600_scu *scu) 246f51926eeSryan_chen { 247*bbbfb0c5Sryan_chen u32 clkin = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL); 248f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel1); 249f51926eeSryan_chen u32 div = (clk_sel >> 12) & 0x7; 250f51926eeSryan_chen 251f51926eeSryan_chen div = (div + 1) << 2; 252f51926eeSryan_chen 253f51926eeSryan_chen return (clkin / div); 254f51926eeSryan_chen } 255f51926eeSryan_chen 256f51926eeSryan_chen static u32 ast2600_get_uart_clk_rate(struct ast2600_scu *scu, int uart_idx) 25727881d20Sryan_chen { 25827881d20Sryan_chen u32 uart_sel = readl(&scu->clk_sel4); 25927881d20Sryan_chen u32 uart_sel5 = readl(&scu->clk_sel5); 26027881d20Sryan_chen ulong uart_clk = 0; 26127881d20Sryan_chen 26227881d20Sryan_chen switch(uart_idx) { 26327881d20Sryan_chen case 1: 26427881d20Sryan_chen case 2: 26527881d20Sryan_chen case 3: 26627881d20Sryan_chen case 4: 26727881d20Sryan_chen case 6: 26827881d20Sryan_chen if(uart_sel & BIT(uart_idx - 1)) 26927881d20Sryan_chen uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ; 270550e691bSryan_chen else 27127881d20Sryan_chen uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ; 27227881d20Sryan_chen break; 27327881d20Sryan_chen case 5: //24mhz is come form usb phy 48Mhz 27427881d20Sryan_chen { 27527881d20Sryan_chen u8 uart5_clk_sel = 0; 27627881d20Sryan_chen //high bit 27727881d20Sryan_chen if (readl(&scu->misc_ctrl1) & BIT(12)) 27827881d20Sryan_chen uart5_clk_sel = 0x2; 27927881d20Sryan_chen else 28027881d20Sryan_chen uart5_clk_sel = 0x0; 281550e691bSryan_chen 28227881d20Sryan_chen if (readl(&scu->clk_sel2) & BIT(14)) 28327881d20Sryan_chen uart5_clk_sel |= 0x1; 284550e691bSryan_chen 28527881d20Sryan_chen switch(uart5_clk_sel) { 28627881d20Sryan_chen case 0: 28727881d20Sryan_chen uart_clk = 24000000; 28827881d20Sryan_chen break; 28927881d20Sryan_chen case 1: 29027881d20Sryan_chen uart_clk = 0; 29127881d20Sryan_chen break; 29227881d20Sryan_chen case 2: 29327881d20Sryan_chen uart_clk = 24000000/13; 29427881d20Sryan_chen break; 29527881d20Sryan_chen case 3: 29627881d20Sryan_chen uart_clk = 192000000/13; 29727881d20Sryan_chen break; 29827881d20Sryan_chen } 29927881d20Sryan_chen } 30027881d20Sryan_chen break; 30127881d20Sryan_chen case 7: 30227881d20Sryan_chen case 8: 30327881d20Sryan_chen case 9: 30427881d20Sryan_chen case 10: 30527881d20Sryan_chen case 11: 30627881d20Sryan_chen case 12: 30727881d20Sryan_chen case 13: 30827881d20Sryan_chen if(uart_sel5 & BIT(uart_idx - 1)) 30927881d20Sryan_chen uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ; 31027881d20Sryan_chen else 31127881d20Sryan_chen uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ; 31227881d20Sryan_chen break; 31327881d20Sryan_chen } 31427881d20Sryan_chen 31527881d20Sryan_chen return uart_clk; 316550e691bSryan_chen } 317550e691bSryan_chen 318feb42054Sryan_chen static ulong ast2600_clk_get_rate(struct clk *clk) 319feb42054Sryan_chen { 320feb42054Sryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 321feb42054Sryan_chen ulong rate = 0; 322feb42054Sryan_chen 323feb42054Sryan_chen switch (clk->id) { 324feb42054Sryan_chen case ASPEED_CLK_HPLL: 325*bbbfb0c5Sryan_chen case ASPEED_CLK_EPLL: 326*bbbfb0c5Sryan_chen case ASPEED_CLK_DPLL: 327d812df15Sryan_chen case ASPEED_CLK_MPLL: 328*bbbfb0c5Sryan_chen rate = ast2600_get_pll_rate(priv->scu, clk->id); 329d812df15Sryan_chen break; 330feb42054Sryan_chen case ASPEED_CLK_AHB: 331feb42054Sryan_chen rate = ast2600_get_hclk(priv->scu); 332feb42054Sryan_chen break; 333feb42054Sryan_chen case ASPEED_CLK_APB: 3342717883aSryan_chen rate = ast2600_get_pclk(priv->scu); 335feb42054Sryan_chen break; 336*bbbfb0c5Sryan_chen case ASPEED_CLK_APLL: 337*bbbfb0c5Sryan_chen rate = ast2600_get_apll_rate(priv->scu); 338*bbbfb0c5Sryan_chen break; 339feb42054Sryan_chen case ASPEED_CLK_GATE_UART1CLK: 340feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 1); 341feb42054Sryan_chen break; 342feb42054Sryan_chen case ASPEED_CLK_GATE_UART2CLK: 343feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 2); 344feb42054Sryan_chen break; 345feb42054Sryan_chen case ASPEED_CLK_GATE_UART3CLK: 346feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 3); 347feb42054Sryan_chen break; 348feb42054Sryan_chen case ASPEED_CLK_GATE_UART4CLK: 349feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 4); 350feb42054Sryan_chen break; 351feb42054Sryan_chen case ASPEED_CLK_GATE_UART5CLK: 352feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 5); 353feb42054Sryan_chen break; 354f51926eeSryan_chen case ASPEED_CLK_SDIO: 355f51926eeSryan_chen rate = ast2600_get_sdio_clk_rate(priv->scu); 356f51926eeSryan_chen break; 357f51926eeSryan_chen case ASPEED_CLK_EMMC: 358f51926eeSryan_chen rate = ast2600_get_emmc_clk_rate(priv->scu); 359f51926eeSryan_chen break; 360feb42054Sryan_chen default: 361d812df15Sryan_chen pr_debug("can't get clk rate \n"); 362feb42054Sryan_chen return -ENOENT; 363d812df15Sryan_chen break; 364feb42054Sryan_chen } 365feb42054Sryan_chen 366feb42054Sryan_chen return rate; 367feb42054Sryan_chen } 368feb42054Sryan_chen 369550e691bSryan_chen struct aspeed_clock_config { 370550e691bSryan_chen ulong input_rate; 371550e691bSryan_chen ulong rate; 37239283ea7Sryan_chen struct ast2600_div_config cfg; 373550e691bSryan_chen }; 374550e691bSryan_chen 375550e691bSryan_chen static const struct aspeed_clock_config aspeed_clock_config_defaults[] = { 3761cd71a14SDylan Hung { 25000000, 400000000, { .num = 95, .denum = 2, .post_div = 1 } }, 377550e691bSryan_chen }; 378550e691bSryan_chen 379550e691bSryan_chen static bool aspeed_get_clock_config_default(ulong input_rate, 380550e691bSryan_chen ulong requested_rate, 38139283ea7Sryan_chen struct ast2600_div_config *cfg) 382550e691bSryan_chen { 383550e691bSryan_chen int i; 384550e691bSryan_chen 385550e691bSryan_chen for (i = 0; i < ARRAY_SIZE(aspeed_clock_config_defaults); i++) { 386550e691bSryan_chen const struct aspeed_clock_config *default_cfg = 387550e691bSryan_chen &aspeed_clock_config_defaults[i]; 388550e691bSryan_chen if (default_cfg->input_rate == input_rate && 389550e691bSryan_chen default_cfg->rate == requested_rate) { 390550e691bSryan_chen *cfg = default_cfg->cfg; 391550e691bSryan_chen return true; 392550e691bSryan_chen } 393550e691bSryan_chen } 394550e691bSryan_chen 395550e691bSryan_chen return false; 396550e691bSryan_chen } 397550e691bSryan_chen 398550e691bSryan_chen /* 399550e691bSryan_chen * @input_rate - the rate of input clock in Hz 400550e691bSryan_chen * @requested_rate - desired output rate in Hz 401550e691bSryan_chen * @div - this is an IN/OUT parameter, at input all fields of the config 402550e691bSryan_chen * need to be set to their maximum allowed values. 403550e691bSryan_chen * The result (the best config we could find), would also be returned 404550e691bSryan_chen * in this structure. 405550e691bSryan_chen * 406550e691bSryan_chen * @return The clock rate, when the resulting div_config is used. 407550e691bSryan_chen */ 408550e691bSryan_chen static ulong aspeed_calc_clock_config(ulong input_rate, ulong requested_rate, 40939283ea7Sryan_chen struct ast2600_div_config *cfg) 410550e691bSryan_chen { 411550e691bSryan_chen /* 412550e691bSryan_chen * The assumption is that kHz precision is good enough and 413550e691bSryan_chen * also enough to avoid overflow when multiplying. 414550e691bSryan_chen */ 415550e691bSryan_chen const ulong input_rate_khz = input_rate / 1000; 416550e691bSryan_chen const ulong rate_khz = requested_rate / 1000; 41739283ea7Sryan_chen const struct ast2600_div_config max_vals = *cfg; 41839283ea7Sryan_chen struct ast2600_div_config it = { 0, 0, 0 }; 419550e691bSryan_chen ulong delta = rate_khz; 420550e691bSryan_chen ulong new_rate_khz = 0; 421550e691bSryan_chen 422550e691bSryan_chen /* 423550e691bSryan_chen * Look for a well known frequency first. 424550e691bSryan_chen */ 425550e691bSryan_chen if (aspeed_get_clock_config_default(input_rate, requested_rate, cfg)) 426550e691bSryan_chen return requested_rate; 427550e691bSryan_chen 428550e691bSryan_chen for (; it.denum <= max_vals.denum; ++it.denum) { 429550e691bSryan_chen for (it.post_div = 0; it.post_div <= max_vals.post_div; 430550e691bSryan_chen ++it.post_div) { 431550e691bSryan_chen it.num = (rate_khz * (it.post_div + 1) / input_rate_khz) 432550e691bSryan_chen * (it.denum + 1); 433550e691bSryan_chen if (it.num > max_vals.num) 434550e691bSryan_chen continue; 435550e691bSryan_chen 436550e691bSryan_chen new_rate_khz = (input_rate_khz 437550e691bSryan_chen * ((it.num + 1) / (it.denum + 1))) 438550e691bSryan_chen / (it.post_div + 1); 439550e691bSryan_chen 440550e691bSryan_chen /* Keep the rate below requested one. */ 441550e691bSryan_chen if (new_rate_khz > rate_khz) 442550e691bSryan_chen continue; 443550e691bSryan_chen 444550e691bSryan_chen if (new_rate_khz - rate_khz < delta) { 445550e691bSryan_chen delta = new_rate_khz - rate_khz; 446550e691bSryan_chen *cfg = it; 447550e691bSryan_chen if (delta == 0) 448550e691bSryan_chen return new_rate_khz * 1000; 449550e691bSryan_chen } 450550e691bSryan_chen } 451550e691bSryan_chen } 452550e691bSryan_chen 453550e691bSryan_chen return new_rate_khz * 1000; 454550e691bSryan_chen } 455550e691bSryan_chen 456feb42054Sryan_chen static u32 ast2600_configure_ddr(struct ast2600_scu *scu, ulong rate) 457550e691bSryan_chen { 458d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 459550e691bSryan_chen u32 mpll_reg; 46039283ea7Sryan_chen struct ast2600_div_config div_cfg = { 461e9526877SDylan Hung .num = 0x1fff, /* SCU220 bit[12:0] */ 462e9526877SDylan Hung .denum = 0x3f, /* SCU220 bit[18:13] */ 463e9526877SDylan Hung .post_div = 0xf, /* SCU220 bit[22:19] */ 464550e691bSryan_chen }; 465550e691bSryan_chen 466550e691bSryan_chen aspeed_calc_clock_config(clkin, rate, &div_cfg); 467550e691bSryan_chen 468feb42054Sryan_chen mpll_reg = readl(&scu->m_pll_param); 469e9526877SDylan Hung mpll_reg &= ~0x7fffff; 470e9526877SDylan Hung mpll_reg |= (div_cfg.post_div << 19) 471e9526877SDylan Hung | (div_cfg.denum << 13) 472e9526877SDylan Hung | (div_cfg.num << 0); 473550e691bSryan_chen 474feb42054Sryan_chen writel(mpll_reg, &scu->m_pll_param); 475550e691bSryan_chen 476*bbbfb0c5Sryan_chen return ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL); 477d6e349c7Sryan_chen } 478d6e349c7Sryan_chen 479d6e349c7Sryan_chen static ulong ast2600_clk_set_rate(struct clk *clk, ulong rate) 480550e691bSryan_chen { 481f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 482550e691bSryan_chen 483550e691bSryan_chen ulong new_rate; 484550e691bSryan_chen switch (clk->id) { 485f0d895afSryan_chen case ASPEED_CLK_MPLL: 486feb42054Sryan_chen new_rate = ast2600_configure_ddr(priv->scu, rate); 487550e691bSryan_chen break; 488550e691bSryan_chen default: 489550e691bSryan_chen return -ENOENT; 490550e691bSryan_chen } 491550e691bSryan_chen 492550e691bSryan_chen return new_rate; 493550e691bSryan_chen } 494feb42054Sryan_chen 495f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC1 (20) 496f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC2 (21) 497f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC3 (20) 498f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC4 (21) 499f9aa0ee1Sryan_chen 500f9aa0ee1Sryan_chen static u32 ast2600_configure_mac(struct ast2600_scu *scu, int index) 501f9aa0ee1Sryan_chen { 502f9aa0ee1Sryan_chen u32 reset_bit; 503f9aa0ee1Sryan_chen u32 clkstop_bit; 504f9aa0ee1Sryan_chen 505f9aa0ee1Sryan_chen 506f9aa0ee1Sryan_chen switch (index) { 507f9aa0ee1Sryan_chen case 1: 508f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC1); 509f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC1); 510f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl1); 511f9aa0ee1Sryan_chen udelay(100); 512f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 513f9aa0ee1Sryan_chen mdelay(10); 514f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 515f9aa0ee1Sryan_chen 516f9aa0ee1Sryan_chen break; 517f9aa0ee1Sryan_chen case 2: 518f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC2); 519f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC2); 520f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl1); 521f9aa0ee1Sryan_chen udelay(100); 522f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 523f9aa0ee1Sryan_chen mdelay(10); 524f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 525f9aa0ee1Sryan_chen break; 526f9aa0ee1Sryan_chen case 3: 527f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC3 - 32); 528f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC3); 529f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 530f9aa0ee1Sryan_chen udelay(100); 531f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 532f9aa0ee1Sryan_chen mdelay(10); 533f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 534f9aa0ee1Sryan_chen break; 535f9aa0ee1Sryan_chen case 4: 536f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC4 - 32); 537f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC4); 538f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 539f9aa0ee1Sryan_chen udelay(100); 540f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 541f9aa0ee1Sryan_chen mdelay(10); 542f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 543f9aa0ee1Sryan_chen break; 544f9aa0ee1Sryan_chen default: 545f9aa0ee1Sryan_chen return -EINVAL; 546f9aa0ee1Sryan_chen } 547f9aa0ee1Sryan_chen 548f9aa0ee1Sryan_chen return 0; 549f9aa0ee1Sryan_chen } 550550e691bSryan_chen 551f51926eeSryan_chen #define SCU_CLKSTOP_SDIO 4 552f51926eeSryan_chen static ulong ast2600_enable_sdclk(struct ast2600_scu *scu) 553f51926eeSryan_chen { 554f51926eeSryan_chen u32 reset_bit; 555f51926eeSryan_chen u32 clkstop_bit; 556f51926eeSryan_chen 557f51926eeSryan_chen reset_bit = BIT(ASPEED_RESET_SD - 32); 558f51926eeSryan_chen clkstop_bit = BIT(SCU_CLKSTOP_SDIO); 559f51926eeSryan_chen 560f51926eeSryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 561f51926eeSryan_chen udelay(100); 562f51926eeSryan_chen //enable clk 563f51926eeSryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 564f51926eeSryan_chen mdelay(10); 565f51926eeSryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 566f51926eeSryan_chen 567f51926eeSryan_chen return 0; 568f51926eeSryan_chen } 569f51926eeSryan_chen 570f51926eeSryan_chen #define SCU_CLKSTOP_EXTSD 31 571f51926eeSryan_chen #define SCU_CLK_SD_MASK (0x7 << 28) 572f51926eeSryan_chen #define SCU_CLK_SD_DIV(x) (x << 28) 573f51926eeSryan_chen 574f51926eeSryan_chen static ulong ast2600_enable_extsdclk(struct ast2600_scu *scu) 575f51926eeSryan_chen { 576f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel4); 577f51926eeSryan_chen u32 enableclk_bit; 578f51926eeSryan_chen 579f51926eeSryan_chen enableclk_bit = BIT(SCU_CLKSTOP_EXTSD); 580f51926eeSryan_chen 581f51926eeSryan_chen clk_sel &= ~SCU_CLK_SD_MASK; 582f51926eeSryan_chen clk_sel |= SCU_CLK_SD_DIV(0); 583f51926eeSryan_chen writel(clk_sel, &scu->clk_sel4); 584f51926eeSryan_chen 585f51926eeSryan_chen //enable clk 586f51926eeSryan_chen setbits_le32(&scu->clk_sel4, enableclk_bit); 587f51926eeSryan_chen 588f51926eeSryan_chen return 0; 589f51926eeSryan_chen } 590f51926eeSryan_chen 591f51926eeSryan_chen #define SCU_CLKSTOP_EMMC 27 592f51926eeSryan_chen static ulong ast2600_enable_emmcclk(struct ast2600_scu *scu) 593f51926eeSryan_chen { 594f51926eeSryan_chen u32 reset_bit; 595f51926eeSryan_chen u32 clkstop_bit; 596f51926eeSryan_chen 597f51926eeSryan_chen reset_bit = BIT(ASPEED_RESET_EMMC); 598f51926eeSryan_chen clkstop_bit = BIT(SCU_CLKSTOP_EMMC); 599f51926eeSryan_chen 600f51926eeSryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 601f51926eeSryan_chen udelay(100); 602f51926eeSryan_chen //enable clk 603f51926eeSryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 604f51926eeSryan_chen mdelay(10); 605f51926eeSryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 606f51926eeSryan_chen 607f51926eeSryan_chen return 0; 608f51926eeSryan_chen } 609f51926eeSryan_chen 610f51926eeSryan_chen #define SCU_CLKSTOP_EXTEMMC 15 611f51926eeSryan_chen #define SCU_CLK_EMMC_MASK (0x7 << 12) 612f51926eeSryan_chen #define SCU_CLK_EMMC_DIV(x) (x << 12) 613f51926eeSryan_chen 614f51926eeSryan_chen static ulong ast2600_enable_extemmcclk(struct ast2600_scu *scu) 615f51926eeSryan_chen { 616f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel1); 617f51926eeSryan_chen u32 enableclk_bit; 618f51926eeSryan_chen 619f51926eeSryan_chen enableclk_bit = BIT(SCU_CLKSTOP_EXTSD); 620f51926eeSryan_chen 621f51926eeSryan_chen clk_sel &= ~SCU_CLK_SD_MASK; 622f51926eeSryan_chen clk_sel |= SCU_CLK_SD_DIV(1); 623f51926eeSryan_chen writel(clk_sel, &scu->clk_sel1); 624f51926eeSryan_chen 625f51926eeSryan_chen //enable clk 626f51926eeSryan_chen setbits_le32(&scu->clk_sel1, enableclk_bit); 627f51926eeSryan_chen 628f51926eeSryan_chen return 0; 629f51926eeSryan_chen } 630f51926eeSryan_chen 631d6e349c7Sryan_chen static int ast2600_clk_enable(struct clk *clk) 632550e691bSryan_chen { 633f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 634550e691bSryan_chen 635550e691bSryan_chen switch (clk->id) { 63686f91560Sryan_chen case ASPEED_CLK_GATE_MAC1CLK: 63786f91560Sryan_chen ast2600_configure_mac(priv->scu, 1); 638550e691bSryan_chen break; 63986f91560Sryan_chen case ASPEED_CLK_GATE_MAC2CLK: 64086f91560Sryan_chen ast2600_configure_mac(priv->scu, 2); 641550e691bSryan_chen break; 64277843939Sryan_chen case ASPEED_CLK_GATE_MAC3CLK: 64377843939Sryan_chen ast2600_configure_mac(priv->scu, 3); 64477843939Sryan_chen break; 64577843939Sryan_chen case ASPEED_CLK_GATE_MAC4CLK: 64677843939Sryan_chen ast2600_configure_mac(priv->scu, 4); 64777843939Sryan_chen break; 648f51926eeSryan_chen case ASPEED_CLK_GATE_SDCLK: 649f51926eeSryan_chen ast2600_enable_sdclk(priv->scu); 650f51926eeSryan_chen break; 651f51926eeSryan_chen case ASPEED_CLK_GATE_SDEXTCLK: 652f51926eeSryan_chen ast2600_enable_extsdclk(priv->scu); 653f51926eeSryan_chen break; 654f51926eeSryan_chen case ASPEED_CLK_GATE_EMMCCLK: 655f51926eeSryan_chen ast2600_enable_emmcclk(priv->scu); 656f51926eeSryan_chen break; 657f51926eeSryan_chen case ASPEED_CLK_GATE_EMMCEXTCLK: 658f51926eeSryan_chen ast2600_enable_extemmcclk(priv->scu); 659f51926eeSryan_chen break; 660550e691bSryan_chen default: 661f9aa0ee1Sryan_chen pr_debug("can't enable clk \n"); 662550e691bSryan_chen return -ENOENT; 66377843939Sryan_chen break; 664550e691bSryan_chen } 665550e691bSryan_chen 666550e691bSryan_chen return 0; 667550e691bSryan_chen } 668550e691bSryan_chen 669f9aa0ee1Sryan_chen struct clk_ops ast2600_clk_ops = { 670d6e349c7Sryan_chen .get_rate = ast2600_clk_get_rate, 671d6e349c7Sryan_chen .set_rate = ast2600_clk_set_rate, 672d6e349c7Sryan_chen .enable = ast2600_clk_enable, 673550e691bSryan_chen }; 674550e691bSryan_chen 675d6e349c7Sryan_chen static int ast2600_clk_probe(struct udevice *dev) 676550e691bSryan_chen { 677f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(dev); 678550e691bSryan_chen 679f0d895afSryan_chen priv->scu = devfdt_get_addr_ptr(dev); 680f0d895afSryan_chen if (IS_ERR(priv->scu)) 681f0d895afSryan_chen return PTR_ERR(priv->scu); 682550e691bSryan_chen 683550e691bSryan_chen return 0; 684550e691bSryan_chen } 685550e691bSryan_chen 686d6e349c7Sryan_chen static int ast2600_clk_bind(struct udevice *dev) 687550e691bSryan_chen { 688550e691bSryan_chen int ret; 689550e691bSryan_chen 690550e691bSryan_chen /* The reset driver does not have a device node, so bind it here */ 691550e691bSryan_chen ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev); 692550e691bSryan_chen if (ret) 693550e691bSryan_chen debug("Warning: No reset driver: ret=%d\n", ret); 694550e691bSryan_chen 695550e691bSryan_chen return 0; 696550e691bSryan_chen } 697550e691bSryan_chen 698d35ac78cSryan_chen #if CONFIG_IS_ENABLED(CMD_CLK) 699d35ac78cSryan_chen struct aspeed_clks { 700d35ac78cSryan_chen ulong id; 701d35ac78cSryan_chen const char *name; 702d35ac78cSryan_chen }; 703d35ac78cSryan_chen 704d35ac78cSryan_chen static struct aspeed_clks aspeed_clk_names[] = { 705d35ac78cSryan_chen { ASPEED_CLK_HPLL, "hpll" }, 706d35ac78cSryan_chen { ASPEED_CLK_MPLL, "mpll" }, 707d35ac78cSryan_chen { ASPEED_CLK_APLL, "apll" }, 708d35ac78cSryan_chen { ASPEED_CLK_EPLL, "epll" }, 709d35ac78cSryan_chen { ASPEED_CLK_DPLL, "dpll" }, 710d35ac78cSryan_chen { ASPEED_CLK_AHB, "hclk" }, 711d35ac78cSryan_chen { ASPEED_CLK_APB, "pclk" }, 712d35ac78cSryan_chen }; 713d35ac78cSryan_chen 714d35ac78cSryan_chen int soc_clk_dump(void) 715d35ac78cSryan_chen { 716d35ac78cSryan_chen struct udevice *dev; 717d35ac78cSryan_chen struct clk clk; 718d35ac78cSryan_chen unsigned long rate; 719d35ac78cSryan_chen int i, ret; 720d35ac78cSryan_chen 721d35ac78cSryan_chen ret = uclass_get_device_by_driver(UCLASS_CLK, 722d35ac78cSryan_chen DM_GET_DRIVER(aspeed_scu), &dev); 723d35ac78cSryan_chen if (ret) 724d35ac78cSryan_chen return ret; 725d35ac78cSryan_chen 726d35ac78cSryan_chen printf("Clk\t\tHz\n"); 727d35ac78cSryan_chen 728d35ac78cSryan_chen for (i = 0; i < ARRAY_SIZE(aspeed_clk_names); i++) { 729d35ac78cSryan_chen clk.id = aspeed_clk_names[i].id; 730d35ac78cSryan_chen ret = clk_request(dev, &clk); 731d35ac78cSryan_chen if (ret < 0) { 732d35ac78cSryan_chen debug("%s clk_request() failed: %d\n", __func__, ret); 733d35ac78cSryan_chen continue; 734d35ac78cSryan_chen } 735d35ac78cSryan_chen 736d35ac78cSryan_chen ret = clk_get_rate(&clk); 737d35ac78cSryan_chen rate = ret; 738d35ac78cSryan_chen 739d35ac78cSryan_chen clk_free(&clk); 740d35ac78cSryan_chen 741d35ac78cSryan_chen if (ret == -ENOTSUPP) { 742d35ac78cSryan_chen printf("clk ID %lu not supported yet\n", 743d35ac78cSryan_chen aspeed_clk_names[i].id); 744d35ac78cSryan_chen continue; 745d35ac78cSryan_chen } 746d35ac78cSryan_chen if (ret < 0) { 747d35ac78cSryan_chen printf("%s %lu: get_rate err: %d\n", 748d35ac78cSryan_chen __func__, aspeed_clk_names[i].id, ret); 749d35ac78cSryan_chen continue; 750d35ac78cSryan_chen } 751d35ac78cSryan_chen 752d35ac78cSryan_chen printf("%s(%3lu):\t%lu\n", 753d35ac78cSryan_chen aspeed_clk_names[i].name, aspeed_clk_names[i].id, rate); 754d35ac78cSryan_chen } 755d35ac78cSryan_chen 756d35ac78cSryan_chen return 0; 757d35ac78cSryan_chen } 758d35ac78cSryan_chen #endif 759d35ac78cSryan_chen 760d6e349c7Sryan_chen static const struct udevice_id ast2600_clk_ids[] = { 761d6e349c7Sryan_chen { .compatible = "aspeed,ast2600-scu", }, 762550e691bSryan_chen { } 763550e691bSryan_chen }; 764550e691bSryan_chen 765aa36597fSDylan Hung U_BOOT_DRIVER(aspeed_scu) = { 766aa36597fSDylan Hung .name = "aspeed_scu", 767550e691bSryan_chen .id = UCLASS_CLK, 768d6e349c7Sryan_chen .of_match = ast2600_clk_ids, 769f0d895afSryan_chen .priv_auto_alloc_size = sizeof(struct ast2600_clk_priv), 770f9aa0ee1Sryan_chen .ops = &ast2600_clk_ops, 771d6e349c7Sryan_chen .bind = ast2600_clk_bind, 772d6e349c7Sryan_chen .probe = ast2600_clk_probe, 773550e691bSryan_chen }; 774