1550e691bSryan_chen // SPDX-License-Identifier: GPL-2.0 2550e691bSryan_chen /* 3550e691bSryan_chen * Copyright (C) ASPEED Technology Inc. 4550e691bSryan_chen */ 5550e691bSryan_chen 6550e691bSryan_chen #include <common.h> 7550e691bSryan_chen #include <clk-uclass.h> 8550e691bSryan_chen #include <dm.h> 9550e691bSryan_chen #include <asm/io.h> 10550e691bSryan_chen #include <dm/lists.h> 1162a6bcbfSryan_chen #include <asm/arch/scu_ast2600.h> 12d6e349c7Sryan_chen #include <dt-bindings/clock/ast2600-clock.h> 1339283ea7Sryan_chen #include <dt-bindings/reset/ast2600-reset.h> 14550e691bSryan_chen 15550e691bSryan_chen /* 16550e691bSryan_chen * MAC Clock Delay settings, taken from Aspeed SDK 17550e691bSryan_chen */ 18550e691bSryan_chen #define RGMII_TXCLK_ODLY 8 19550e691bSryan_chen #define RMII_RXCLK_IDLY 2 20550e691bSryan_chen 21ed30249cSDylan Hung #define MAC_DEF_DELAY_1G 0x00410410 22*54f9cba1SDylan Hung #define MAC_DEF_DELAY_100M 0x00410410 23*54f9cba1SDylan Hung #define MAC_DEF_DELAY_10M 0x00410410 24*54f9cba1SDylan Hung 25*54f9cba1SDylan Hung #define MAC34_DEF_DELAY_1G 0x00104208 26*54f9cba1SDylan Hung #define MAC34_DEF_DELAY_100M 0x00104208 27*54f9cba1SDylan Hung #define MAC34_DEF_DELAY_10M 0x00104208 284760b3f8SDylan Hung 29550e691bSryan_chen /* 30550e691bSryan_chen * TGMII Clock Duty constants, taken from Aspeed SDK 31550e691bSryan_chen */ 32550e691bSryan_chen #define RGMII2_TXCK_DUTY 0x66 33550e691bSryan_chen #define RGMII1_TXCK_DUTY 0x64 34550e691bSryan_chen 35550e691bSryan_chen #define D2PLL_DEFAULT_RATE (250 * 1000 * 1000) 36550e691bSryan_chen 37550e691bSryan_chen DECLARE_GLOBAL_DATA_PTR; 38550e691bSryan_chen 39550e691bSryan_chen /* 40550e691bSryan_chen * Clock divider/multiplier configuration struct. 41550e691bSryan_chen * For H-PLL and M-PLL the formula is 42550e691bSryan_chen * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1) 43550e691bSryan_chen * M - Numerator 44550e691bSryan_chen * N - Denumerator 45550e691bSryan_chen * P - Post Divider 46550e691bSryan_chen * They have the same layout in their control register. 47550e691bSryan_chen * 48550e691bSryan_chen * D-PLL and D2-PLL have extra divider (OD + 1), which is not 49550e691bSryan_chen * yet needed and ignored by clock configurations. 50550e691bSryan_chen */ 5139283ea7Sryan_chen struct ast2600_div_config { 52550e691bSryan_chen unsigned int num; 53550e691bSryan_chen unsigned int denum; 54550e691bSryan_chen unsigned int post_div; 55550e691bSryan_chen }; 56550e691bSryan_chen 57bbbfb0c5Sryan_chen extern u32 ast2600_get_pll_rate(struct ast2600_scu *scu, int pll_idx) 58550e691bSryan_chen { 59d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 60bbbfb0c5Sryan_chen u32 pll_reg = 0; 619639db61Sryan_chen unsigned int mult, div = 1; 62550e691bSryan_chen 63bbbfb0c5Sryan_chen switch(pll_idx) { 64bbbfb0c5Sryan_chen case ASPEED_CLK_HPLL: 65bbbfb0c5Sryan_chen pll_reg = readl(&scu->h_pll_param); 66bbbfb0c5Sryan_chen break; 67bbbfb0c5Sryan_chen case ASPEED_CLK_MPLL: 68bbbfb0c5Sryan_chen pll_reg = readl(&scu->m_pll_param); 69bbbfb0c5Sryan_chen break; 70bbbfb0c5Sryan_chen case ASPEED_CLK_DPLL: 71bbbfb0c5Sryan_chen pll_reg = readl(&scu->d_pll_param); 72bbbfb0c5Sryan_chen break; 73bbbfb0c5Sryan_chen case ASPEED_CLK_EPLL: 74bbbfb0c5Sryan_chen pll_reg = readl(&scu->e_pll_param); 75bbbfb0c5Sryan_chen break; 76bbbfb0c5Sryan_chen 77bbbfb0c5Sryan_chen } 78bbbfb0c5Sryan_chen if (pll_reg & BIT(24)) { 799639db61Sryan_chen /* Pass through mode */ 809639db61Sryan_chen mult = div = 1; 819639db61Sryan_chen } else { 829639db61Sryan_chen /* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1) */ 83bbbfb0c5Sryan_chen u32 m = pll_reg & 0x1fff; 84bbbfb0c5Sryan_chen u32 n = (pll_reg >> 13) & 0x3f; 85bbbfb0c5Sryan_chen u32 p = (pll_reg >> 19) & 0xf; 869639db61Sryan_chen mult = (m + 1) / (n + 1); 879639db61Sryan_chen div = (p + 1); 889639db61Sryan_chen } 899639db61Sryan_chen return ((clkin * mult)/div); 90550e691bSryan_chen 91550e691bSryan_chen } 92550e691bSryan_chen 934f22e838Sryan_chen extern u32 ast2600_get_apll_rate(struct ast2600_scu *scu) 94550e691bSryan_chen { 95bbbfb0c5Sryan_chen u32 clkin = AST2600_CLK_IN; 9639283ea7Sryan_chen u32 apll_reg = readl(&scu->a_pll_param); 9739283ea7Sryan_chen unsigned int mult, div = 1; 98d6e349c7Sryan_chen 9939283ea7Sryan_chen if (apll_reg & BIT(20)) { 100d6e349c7Sryan_chen /* Pass through mode */ 101d6e349c7Sryan_chen mult = div = 1; 102d6e349c7Sryan_chen } else { 103bbbfb0c5Sryan_chen /* F = 25Mhz * (2-od) * [(m + 2) / (n + 1)] */ 10439283ea7Sryan_chen u32 m = (apll_reg >> 5) & 0x3f; 10539283ea7Sryan_chen u32 od = (apll_reg >> 4) & 0x1; 10639283ea7Sryan_chen u32 n = apll_reg & 0xf; 107d6e349c7Sryan_chen 108bbbfb0c5Sryan_chen mult = (2 - od) * (m + 2); 109bbbfb0c5Sryan_chen div = n + 1; 110d6e349c7Sryan_chen } 111bbbfb0c5Sryan_chen return ((clkin * mult)/div); 11239283ea7Sryan_chen } 11339283ea7Sryan_chen 114d812df15Sryan_chen static u32 ast2600_a0_axi_ahb_div_table[] = { 115d812df15Sryan_chen 2, 2, 3, 5, 116d812df15Sryan_chen }; 117d812df15Sryan_chen 118d812df15Sryan_chen static u32 ast2600_a1_axi_ahb_div_table[] = { 119d812df15Sryan_chen 4, 6, 2, 4, 120d812df15Sryan_chen }; 121d812df15Sryan_chen 122d812df15Sryan_chen static u32 ast2600_get_hclk(struct ast2600_scu *scu) 123d812df15Sryan_chen { 124d812df15Sryan_chen u32 hw_rev = readl(&scu->chip_id0); 125d812df15Sryan_chen u32 hwstrap1 = readl(&scu->hwstrap1); 126d812df15Sryan_chen u32 axi_div = 1; 127d812df15Sryan_chen u32 ahb_div = 0; 128d812df15Sryan_chen u32 rate = 0; 129d812df15Sryan_chen 130c29e1cc8Sryan_chen if(hwstrap1 & BIT(16)) 131d812df15Sryan_chen axi_div = 1; 132d812df15Sryan_chen else 133d812df15Sryan_chen axi_div = 2; 134d812df15Sryan_chen 135d812df15Sryan_chen if (hw_rev & BIT(16)) 136d812df15Sryan_chen ahb_div = ast2600_a1_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 137d812df15Sryan_chen else 138d812df15Sryan_chen ahb_div = ast2600_a0_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 139d812df15Sryan_chen 140bbbfb0c5Sryan_chen rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL); 141d812df15Sryan_chen 1422717883aSryan_chen return (rate / axi_div / ahb_div); 1432717883aSryan_chen } 1442717883aSryan_chen 1452717883aSryan_chen static u32 ast2600_hpll_pclk_div_table[] = { 1462717883aSryan_chen 4, 8, 12, 16, 20, 24, 28, 32, 1472717883aSryan_chen }; 1482717883aSryan_chen 1492717883aSryan_chen static u32 ast2600_get_pclk(struct ast2600_scu *scu) 1502717883aSryan_chen { 1512717883aSryan_chen u32 clk_sel1 = readl(&scu->clk_sel1); 1522717883aSryan_chen u32 apb_div = ast2600_hpll_pclk_div_table[((clk_sel1 >> 23) & 0x7)]; 153bbbfb0c5Sryan_chen u32 rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL); 1542717883aSryan_chen 1552717883aSryan_chen return (rate / apb_div); 156d812df15Sryan_chen } 157d812df15Sryan_chen 15827881d20Sryan_chen static u32 ast2600_get_uxclk_rate(struct ast2600_scu *scu) 159d6e349c7Sryan_chen { 16027881d20Sryan_chen u32 clk_in = 0; 16127881d20Sryan_chen u32 uxclk_sel = readl(&scu->clk_sel4); 162550e691bSryan_chen 16327881d20Sryan_chen uxclk_sel &= 0x3; 16427881d20Sryan_chen switch(uxclk_sel) { 16527881d20Sryan_chen case 0: 16627881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 4; 16727881d20Sryan_chen break; 16827881d20Sryan_chen case 1: 16927881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 2; 17027881d20Sryan_chen break; 17127881d20Sryan_chen case 2: 17227881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu); 17327881d20Sryan_chen break; 17427881d20Sryan_chen case 3: 17527881d20Sryan_chen clk_in = ast2600_get_hclk(scu); 17627881d20Sryan_chen break; 17727881d20Sryan_chen } 178d6e349c7Sryan_chen 17927881d20Sryan_chen return clk_in; 18027881d20Sryan_chen } 18127881d20Sryan_chen 18227881d20Sryan_chen static u32 ast2600_get_huxclk_rate(struct ast2600_scu *scu) 18327881d20Sryan_chen { 18427881d20Sryan_chen u32 clk_in = 0; 18527881d20Sryan_chen u32 huclk_sel = readl(&scu->clk_sel4); 18627881d20Sryan_chen 18727881d20Sryan_chen huclk_sel = ((huclk_sel >> 3) & 0x3); 18827881d20Sryan_chen switch(huclk_sel) { 18927881d20Sryan_chen case 0: 19027881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 4; 19127881d20Sryan_chen break; 19227881d20Sryan_chen case 1: 19327881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 2; 19427881d20Sryan_chen break; 19527881d20Sryan_chen case 2: 19627881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu); 19727881d20Sryan_chen break; 19827881d20Sryan_chen case 3: 19927881d20Sryan_chen clk_in = ast2600_get_hclk(scu); 20027881d20Sryan_chen break; 20127881d20Sryan_chen } 20227881d20Sryan_chen 20327881d20Sryan_chen return clk_in; 20427881d20Sryan_chen } 20527881d20Sryan_chen 20627881d20Sryan_chen static u32 ast2600_get_uart_from_uxclk_rate(struct ast2600_scu *scu) 20727881d20Sryan_chen { 20827881d20Sryan_chen u32 clk_in = ast2600_get_uxclk_rate(scu); 20927881d20Sryan_chen u32 div_reg = readl(&scu->uart_24m_ref_uxclk); 21027881d20Sryan_chen unsigned int mult, div; 21127881d20Sryan_chen 21227881d20Sryan_chen u32 n = (div_reg >> 8) & 0x3ff; 21327881d20Sryan_chen u32 r = div_reg & 0xff; 21427881d20Sryan_chen 21527881d20Sryan_chen mult = r; 21627881d20Sryan_chen div = (n * 4); 21727881d20Sryan_chen return (clk_in * mult)/div; 21827881d20Sryan_chen } 21927881d20Sryan_chen 22027881d20Sryan_chen static u32 ast2600_get_uart_from_huxclk_rate(struct ast2600_scu *scu) 22127881d20Sryan_chen { 22227881d20Sryan_chen u32 clk_in = ast2600_get_huxclk_rate(scu); 22327881d20Sryan_chen u32 div_reg = readl(&scu->uart_24m_ref_huxclk); 22427881d20Sryan_chen 22527881d20Sryan_chen unsigned int mult, div; 22627881d20Sryan_chen 22727881d20Sryan_chen u32 n = (div_reg >> 8) & 0x3ff; 22827881d20Sryan_chen u32 r = div_reg & 0xff; 22927881d20Sryan_chen 23027881d20Sryan_chen mult = r; 23127881d20Sryan_chen div = (n * 4); 23227881d20Sryan_chen return (clk_in * mult)/div; 23327881d20Sryan_chen } 23427881d20Sryan_chen 235f51926eeSryan_chen static u32 ast2600_get_sdio_clk_rate(struct ast2600_scu *scu) 236f51926eeSryan_chen { 237f51926eeSryan_chen u32 clkin = 0; 238f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel4); 239f51926eeSryan_chen u32 div = (clk_sel >> 28) & 0x7; 240f51926eeSryan_chen 241f51926eeSryan_chen if(clk_sel & BIT(8)) { 242f51926eeSryan_chen clkin = ast2600_get_apll_rate(scu); 243f51926eeSryan_chen } else { 244f51926eeSryan_chen clkin = 200 * 1000 * 1000; 245f51926eeSryan_chen } 246f51926eeSryan_chen div = (div + 1) << 1; 247f51926eeSryan_chen 248f51926eeSryan_chen return (clkin / div); 249f51926eeSryan_chen } 250f51926eeSryan_chen 251f51926eeSryan_chen static u32 ast2600_get_emmc_clk_rate(struct ast2600_scu *scu) 252f51926eeSryan_chen { 253bbbfb0c5Sryan_chen u32 clkin = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL); 254f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel1); 255f51926eeSryan_chen u32 div = (clk_sel >> 12) & 0x7; 256f51926eeSryan_chen 257f51926eeSryan_chen div = (div + 1) << 2; 258f51926eeSryan_chen 259f51926eeSryan_chen return (clkin / div); 260f51926eeSryan_chen } 261f51926eeSryan_chen 262f51926eeSryan_chen static u32 ast2600_get_uart_clk_rate(struct ast2600_scu *scu, int uart_idx) 26327881d20Sryan_chen { 26427881d20Sryan_chen u32 uart_sel = readl(&scu->clk_sel4); 26527881d20Sryan_chen u32 uart_sel5 = readl(&scu->clk_sel5); 26627881d20Sryan_chen ulong uart_clk = 0; 26727881d20Sryan_chen 26827881d20Sryan_chen switch(uart_idx) { 26927881d20Sryan_chen case 1: 27027881d20Sryan_chen case 2: 27127881d20Sryan_chen case 3: 27227881d20Sryan_chen case 4: 27327881d20Sryan_chen case 6: 27427881d20Sryan_chen if(uart_sel & BIT(uart_idx - 1)) 27527881d20Sryan_chen uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ; 276550e691bSryan_chen else 27727881d20Sryan_chen uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ; 27827881d20Sryan_chen break; 27927881d20Sryan_chen case 5: //24mhz is come form usb phy 48Mhz 28027881d20Sryan_chen { 28127881d20Sryan_chen u8 uart5_clk_sel = 0; 28227881d20Sryan_chen //high bit 28327881d20Sryan_chen if (readl(&scu->misc_ctrl1) & BIT(12)) 28427881d20Sryan_chen uart5_clk_sel = 0x2; 28527881d20Sryan_chen else 28627881d20Sryan_chen uart5_clk_sel = 0x0; 287550e691bSryan_chen 28827881d20Sryan_chen if (readl(&scu->clk_sel2) & BIT(14)) 28927881d20Sryan_chen uart5_clk_sel |= 0x1; 290550e691bSryan_chen 29127881d20Sryan_chen switch(uart5_clk_sel) { 29227881d20Sryan_chen case 0: 29327881d20Sryan_chen uart_clk = 24000000; 29427881d20Sryan_chen break; 29527881d20Sryan_chen case 1: 29627881d20Sryan_chen uart_clk = 0; 29727881d20Sryan_chen break; 29827881d20Sryan_chen case 2: 29927881d20Sryan_chen uart_clk = 24000000/13; 30027881d20Sryan_chen break; 30127881d20Sryan_chen case 3: 30227881d20Sryan_chen uart_clk = 192000000/13; 30327881d20Sryan_chen break; 30427881d20Sryan_chen } 30527881d20Sryan_chen } 30627881d20Sryan_chen break; 30727881d20Sryan_chen case 7: 30827881d20Sryan_chen case 8: 30927881d20Sryan_chen case 9: 31027881d20Sryan_chen case 10: 31127881d20Sryan_chen case 11: 31227881d20Sryan_chen case 12: 31327881d20Sryan_chen case 13: 31427881d20Sryan_chen if(uart_sel5 & BIT(uart_idx - 1)) 31527881d20Sryan_chen uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ; 31627881d20Sryan_chen else 31727881d20Sryan_chen uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ; 31827881d20Sryan_chen break; 31927881d20Sryan_chen } 32027881d20Sryan_chen 32127881d20Sryan_chen return uart_clk; 322550e691bSryan_chen } 323550e691bSryan_chen 324feb42054Sryan_chen static ulong ast2600_clk_get_rate(struct clk *clk) 325feb42054Sryan_chen { 326feb42054Sryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 327feb42054Sryan_chen ulong rate = 0; 328feb42054Sryan_chen 329feb42054Sryan_chen switch (clk->id) { 330feb42054Sryan_chen case ASPEED_CLK_HPLL: 331bbbfb0c5Sryan_chen case ASPEED_CLK_EPLL: 332bbbfb0c5Sryan_chen case ASPEED_CLK_DPLL: 333d812df15Sryan_chen case ASPEED_CLK_MPLL: 334bbbfb0c5Sryan_chen rate = ast2600_get_pll_rate(priv->scu, clk->id); 335d812df15Sryan_chen break; 336feb42054Sryan_chen case ASPEED_CLK_AHB: 337feb42054Sryan_chen rate = ast2600_get_hclk(priv->scu); 338feb42054Sryan_chen break; 339feb42054Sryan_chen case ASPEED_CLK_APB: 3402717883aSryan_chen rate = ast2600_get_pclk(priv->scu); 341feb42054Sryan_chen break; 342bbbfb0c5Sryan_chen case ASPEED_CLK_APLL: 343bbbfb0c5Sryan_chen rate = ast2600_get_apll_rate(priv->scu); 344bbbfb0c5Sryan_chen break; 345feb42054Sryan_chen case ASPEED_CLK_GATE_UART1CLK: 346feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 1); 347feb42054Sryan_chen break; 348feb42054Sryan_chen case ASPEED_CLK_GATE_UART2CLK: 349feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 2); 350feb42054Sryan_chen break; 351feb42054Sryan_chen case ASPEED_CLK_GATE_UART3CLK: 352feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 3); 353feb42054Sryan_chen break; 354feb42054Sryan_chen case ASPEED_CLK_GATE_UART4CLK: 355feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 4); 356feb42054Sryan_chen break; 357feb42054Sryan_chen case ASPEED_CLK_GATE_UART5CLK: 358feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 5); 359feb42054Sryan_chen break; 360f51926eeSryan_chen case ASPEED_CLK_SDIO: 361f51926eeSryan_chen rate = ast2600_get_sdio_clk_rate(priv->scu); 362f51926eeSryan_chen break; 363f51926eeSryan_chen case ASPEED_CLK_EMMC: 364f51926eeSryan_chen rate = ast2600_get_emmc_clk_rate(priv->scu); 365f51926eeSryan_chen break; 366feb42054Sryan_chen default: 367d812df15Sryan_chen pr_debug("can't get clk rate \n"); 368feb42054Sryan_chen return -ENOENT; 369d812df15Sryan_chen break; 370feb42054Sryan_chen } 371feb42054Sryan_chen 372feb42054Sryan_chen return rate; 373feb42054Sryan_chen } 374feb42054Sryan_chen 375550e691bSryan_chen struct aspeed_clock_config { 376550e691bSryan_chen ulong input_rate; 377550e691bSryan_chen ulong rate; 37839283ea7Sryan_chen struct ast2600_div_config cfg; 379550e691bSryan_chen }; 380550e691bSryan_chen 381550e691bSryan_chen static const struct aspeed_clock_config aspeed_clock_config_defaults[] = { 3821cd71a14SDylan Hung { 25000000, 400000000, { .num = 95, .denum = 2, .post_div = 1 } }, 38331a90994SDylan Hung { 25000000, 200000000, { .num = 127, .denum = 0, .post_div = 15 } }, 38431a90994SDylan Hung { 25000000, 334000000, { .num = 667, .denum = 4, .post_div = 9 } }, 385cc476ffcSDylan Hung { 25000000, 1000000000, { .num = 119, .denum = 2, .post_div = 0 } }, 386550e691bSryan_chen }; 387550e691bSryan_chen 388550e691bSryan_chen static bool aspeed_get_clock_config_default(ulong input_rate, 389550e691bSryan_chen ulong requested_rate, 39039283ea7Sryan_chen struct ast2600_div_config *cfg) 391550e691bSryan_chen { 392550e691bSryan_chen int i; 393550e691bSryan_chen 394550e691bSryan_chen for (i = 0; i < ARRAY_SIZE(aspeed_clock_config_defaults); i++) { 395550e691bSryan_chen const struct aspeed_clock_config *default_cfg = 396550e691bSryan_chen &aspeed_clock_config_defaults[i]; 397550e691bSryan_chen if (default_cfg->input_rate == input_rate && 398550e691bSryan_chen default_cfg->rate == requested_rate) { 399550e691bSryan_chen *cfg = default_cfg->cfg; 400550e691bSryan_chen return true; 401550e691bSryan_chen } 402550e691bSryan_chen } 403550e691bSryan_chen 404550e691bSryan_chen return false; 405550e691bSryan_chen } 406550e691bSryan_chen 407550e691bSryan_chen /* 408550e691bSryan_chen * @input_rate - the rate of input clock in Hz 409550e691bSryan_chen * @requested_rate - desired output rate in Hz 410550e691bSryan_chen * @div - this is an IN/OUT parameter, at input all fields of the config 411550e691bSryan_chen * need to be set to their maximum allowed values. 412550e691bSryan_chen * The result (the best config we could find), would also be returned 413550e691bSryan_chen * in this structure. 414550e691bSryan_chen * 415550e691bSryan_chen * @return The clock rate, when the resulting div_config is used. 416550e691bSryan_chen */ 417550e691bSryan_chen static ulong aspeed_calc_clock_config(ulong input_rate, ulong requested_rate, 41839283ea7Sryan_chen struct ast2600_div_config *cfg) 419550e691bSryan_chen { 420550e691bSryan_chen /* 421550e691bSryan_chen * The assumption is that kHz precision is good enough and 422550e691bSryan_chen * also enough to avoid overflow when multiplying. 423550e691bSryan_chen */ 424550e691bSryan_chen const ulong input_rate_khz = input_rate / 1000; 425550e691bSryan_chen const ulong rate_khz = requested_rate / 1000; 42639283ea7Sryan_chen const struct ast2600_div_config max_vals = *cfg; 42739283ea7Sryan_chen struct ast2600_div_config it = { 0, 0, 0 }; 428550e691bSryan_chen ulong delta = rate_khz; 429550e691bSryan_chen ulong new_rate_khz = 0; 430550e691bSryan_chen 431550e691bSryan_chen /* 432550e691bSryan_chen * Look for a well known frequency first. 433550e691bSryan_chen */ 434550e691bSryan_chen if (aspeed_get_clock_config_default(input_rate, requested_rate, cfg)) 435550e691bSryan_chen return requested_rate; 436550e691bSryan_chen 437550e691bSryan_chen for (; it.denum <= max_vals.denum; ++it.denum) { 438550e691bSryan_chen for (it.post_div = 0; it.post_div <= max_vals.post_div; 439550e691bSryan_chen ++it.post_div) { 440550e691bSryan_chen it.num = (rate_khz * (it.post_div + 1) / input_rate_khz) 441550e691bSryan_chen * (it.denum + 1); 442550e691bSryan_chen if (it.num > max_vals.num) 443550e691bSryan_chen continue; 444550e691bSryan_chen 445550e691bSryan_chen new_rate_khz = (input_rate_khz 446550e691bSryan_chen * ((it.num + 1) / (it.denum + 1))) 447550e691bSryan_chen / (it.post_div + 1); 448550e691bSryan_chen 449550e691bSryan_chen /* Keep the rate below requested one. */ 450550e691bSryan_chen if (new_rate_khz > rate_khz) 451550e691bSryan_chen continue; 452550e691bSryan_chen 453550e691bSryan_chen if (new_rate_khz - rate_khz < delta) { 454550e691bSryan_chen delta = new_rate_khz - rate_khz; 455550e691bSryan_chen *cfg = it; 456550e691bSryan_chen if (delta == 0) 457550e691bSryan_chen return new_rate_khz * 1000; 458550e691bSryan_chen } 459550e691bSryan_chen } 460550e691bSryan_chen } 461550e691bSryan_chen 462550e691bSryan_chen return new_rate_khz * 1000; 463550e691bSryan_chen } 464550e691bSryan_chen 465feb42054Sryan_chen static u32 ast2600_configure_ddr(struct ast2600_scu *scu, ulong rate) 466550e691bSryan_chen { 467d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 468550e691bSryan_chen u32 mpll_reg; 46939283ea7Sryan_chen struct ast2600_div_config div_cfg = { 470e9526877SDylan Hung .num = 0x1fff, /* SCU220 bit[12:0] */ 471e9526877SDylan Hung .denum = 0x3f, /* SCU220 bit[18:13] */ 472e9526877SDylan Hung .post_div = 0xf, /* SCU220 bit[22:19] */ 473550e691bSryan_chen }; 474550e691bSryan_chen 475550e691bSryan_chen aspeed_calc_clock_config(clkin, rate, &div_cfg); 476550e691bSryan_chen 477feb42054Sryan_chen mpll_reg = readl(&scu->m_pll_param); 478e9526877SDylan Hung mpll_reg &= ~0x7fffff; 479e9526877SDylan Hung mpll_reg |= (div_cfg.post_div << 19) 480e9526877SDylan Hung | (div_cfg.denum << 13) 481e9526877SDylan Hung | (div_cfg.num << 0); 482550e691bSryan_chen 483feb42054Sryan_chen writel(mpll_reg, &scu->m_pll_param); 484550e691bSryan_chen 485cc476ffcSDylan Hung return ast2600_get_pll_rate(scu, ASPEED_CLK_MPLL); 486d6e349c7Sryan_chen } 487d6e349c7Sryan_chen 488d6e349c7Sryan_chen static ulong ast2600_clk_set_rate(struct clk *clk, ulong rate) 489550e691bSryan_chen { 490f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 491550e691bSryan_chen 492550e691bSryan_chen ulong new_rate; 493550e691bSryan_chen switch (clk->id) { 494f0d895afSryan_chen case ASPEED_CLK_MPLL: 495feb42054Sryan_chen new_rate = ast2600_configure_ddr(priv->scu, rate); 496550e691bSryan_chen break; 497550e691bSryan_chen default: 498550e691bSryan_chen return -ENOENT; 499550e691bSryan_chen } 500550e691bSryan_chen 501550e691bSryan_chen return new_rate; 502550e691bSryan_chen } 503feb42054Sryan_chen 504f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC1 (20) 505f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC2 (21) 506f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC3 (20) 507f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC4 (21) 508f9aa0ee1Sryan_chen 509cc476ffcSDylan Hung static u32 ast2600_configure_mac12_clk(struct ast2600_scu *scu) 510cc476ffcSDylan Hung { 511cc476ffcSDylan Hung u32 epll_reg; 512cc476ffcSDylan Hung u32 clksel; 5134760b3f8SDylan Hung u32 clkdelay; 514cc476ffcSDylan Hung 515cc476ffcSDylan Hung struct ast2600_div_config div_cfg = { 516cc476ffcSDylan Hung .num = 0x1fff, /* SCU240 bit[12:0] */ 517cc476ffcSDylan Hung .denum = 0x3f, /* SCU240 bit[18:13] */ 518cc476ffcSDylan Hung .post_div = 0xf, /* SCU240 bit[22:19] */ 519cc476ffcSDylan Hung }; 520cc476ffcSDylan Hung 521cc476ffcSDylan Hung /* configure E-PLL 1000M */ 522cc476ffcSDylan Hung aspeed_calc_clock_config(AST2600_CLK_IN, 1000000000, &div_cfg); 523cc476ffcSDylan Hung epll_reg = readl(&scu->e_pll_param); 524cc476ffcSDylan Hung epll_reg &= ~GENMASK(22, 0); 525cc476ffcSDylan Hung epll_reg |= (div_cfg.post_div << 19) 526cc476ffcSDylan Hung | (div_cfg.denum << 13) 527cc476ffcSDylan Hung | (div_cfg.num << 0); 528cc476ffcSDylan Hung 529cc476ffcSDylan Hung writel(epll_reg, &scu->e_pll_param); 530cc476ffcSDylan Hung 531cc476ffcSDylan Hung /* select MAC#1 and MAC#2 clock source = EPLL / 8 */ 532cc476ffcSDylan Hung clksel = readl(&scu->clk_sel2); 533cc476ffcSDylan Hung clksel &= ~BIT(23); 534cc476ffcSDylan Hung clksel |= 0x7 << 20; 535cc476ffcSDylan Hung writel(clksel, &scu->clk_sel2); 536cc476ffcSDylan Hung 5374760b3f8SDylan Hung /* 5384760b3f8SDylan Hung BIT(31): select RGMII 125M from internal source 5394760b3f8SDylan Hung BIT(28): RGMII 125M output enable 5404760b3f8SDylan Hung BIT(25:0): 1G default delay 5414760b3f8SDylan Hung */ 5424760b3f8SDylan Hung clkdelay = MAC_DEF_DELAY_1G | BIT(31) | BIT(28); 5434760b3f8SDylan Hung writel(clkdelay, &scu->mac12_clk_delay); 5444760b3f8SDylan Hung 5454760b3f8SDylan Hung /* set 100M/10M default delay */ 5464760b3f8SDylan Hung writel(MAC_DEF_DELAY_100M, &scu->mac12_clk_delay_100M); 5474760b3f8SDylan Hung writel(MAC_DEF_DELAY_10M, &scu->mac12_clk_delay_10M); 548cc476ffcSDylan Hung 549ed30249cSDylan Hung /* MAC AHB = HPLL / 6 */ 550894c19cfSDylan Hung clksel = readl(&scu->clk_sel1); 551894c19cfSDylan Hung clksel &= ~GENMASK(18, 16); 552ed30249cSDylan Hung clksel |= 0x2 << 16; 553894c19cfSDylan Hung writel(clksel, &scu->clk_sel1); 554894c19cfSDylan Hung 555cc476ffcSDylan Hung return 0; 556cc476ffcSDylan Hung } 557cc476ffcSDylan Hung 558*54f9cba1SDylan Hung static u32 ast2600_configure_mac34_clk(struct ast2600_scu *scu) 559*54f9cba1SDylan Hung { 560*54f9cba1SDylan Hung u32 reg; 561*54f9cba1SDylan Hung 562*54f9cba1SDylan Hung ast2600_configure_mac12_clk(scu); 563*54f9cba1SDylan Hung 564*54f9cba1SDylan Hung /* 565*54f9cba1SDylan Hung BIT[31] RGMII 125M source: 0 = from IO pin 566*54f9cba1SDylan Hung BIT[25:0] MAC 1G delay 567*54f9cba1SDylan Hung */ 568*54f9cba1SDylan Hung reg = readl(&scu->mac34_clk_delay); 569*54f9cba1SDylan Hung reg &= ~(BIT(31) | GENMASK(25, 0)); 570*54f9cba1SDylan Hung reg |= MAC34_DEF_DELAY_1G; 571*54f9cba1SDylan Hung writel(reg, &scu->mac34_clk_delay); 572*54f9cba1SDylan Hung writel(MAC34_DEF_DELAY_100M, &scu->mac34_clk_delay_100M); 573*54f9cba1SDylan Hung writel(MAC34_DEF_DELAY_10M, &scu->mac34_clk_delay_10M); 574*54f9cba1SDylan Hung 575*54f9cba1SDylan Hung /* clock source seletion and divider */ 576*54f9cba1SDylan Hung reg = readl(&scu->clk_sel4); 577*54f9cba1SDylan Hung reg &= ~GENMASK(26, 24); /* MAC AHB = HCLK / 2 */ 578*54f9cba1SDylan Hung reg &= ~GENMASK(18, 16); 579*54f9cba1SDylan Hung reg |= 0x3 << 16; /* RMII 50M = SLICLK_200M / 4 */ 580*54f9cba1SDylan Hung writel(reg, &scu->clk_sel4); 581*54f9cba1SDylan Hung 582*54f9cba1SDylan Hung /* set driving strength */ 583*54f9cba1SDylan Hung reg = readl(&scu->pinmux_ctrl16); 584*54f9cba1SDylan Hung reg &= GENMASK(3, 0); 585*54f9cba1SDylan Hung reg |= (0x2 << 0) | (0x2 << 2); 586*54f9cba1SDylan Hung writel(reg, &scu->pinmux_ctrl16); 587*54f9cba1SDylan Hung 588*54f9cba1SDylan Hung return 0; 589*54f9cba1SDylan Hung } 590*54f9cba1SDylan Hung #if 0 591*54f9cba1SDylan Hung /** 592*54f9cba1SDylan Hung * WIP: ast2600 RGMII clock source tree 593*54f9cba1SDylan Hung * 594*54f9cba1SDylan Hung * 125M from external PAD -------->|\ 595*54f9cba1SDylan Hung * HPLL -->|\ | |---->RGMII 125M for MAC#1 & MAC#2 596*54f9cba1SDylan Hung * | |---->| divider |---->|/ + 597*54f9cba1SDylan Hung * EPLL -->|/ | 598*54f9cba1SDylan Hung * | 599*54f9cba1SDylan Hung * +---------<-----------|PAD output enable|<---------------------+ 600*54f9cba1SDylan Hung * | 601*54f9cba1SDylan Hung * +--->|PAD input enable|----->|\ 602*54f9cba1SDylan Hung * | |----> RGMII 125M for MAC#3 & MAC#4 603*54f9cba1SDylan Hung * SLICLK 200M -->|divider|---->|/ 604*54f9cba1SDylan Hung */ 605*54f9cba1SDylan Hung struct ast2600_rgmii_clk_config { 606*54f9cba1SDylan Hung u32 mac_1_2_src; /* 0=external PAD, 1=internal PLL */ 607*54f9cba1SDylan Hung u32 int_clk_src; /* 0=EPLL, 1=HPLL */ 608*54f9cba1SDylan Hung u32 int_clk_div; 609*54f9cba1SDylan Hung 610*54f9cba1SDylan Hung u32 mac_3_4_src; /* 0=external PAD, 1=SLICLK */ 611*54f9cba1SDylan Hung u32 sli_clk_div; /* reserved */ 612*54f9cba1SDylan Hung }; 613*54f9cba1SDylan Hung 614*54f9cba1SDylan Hung static void ast2600_init_rgmii_clk(struct ast2600_scu *scu, int index) 615*54f9cba1SDylan Hung { 616*54f9cba1SDylan Hung debug("%s not ready\n", __func__); 617*54f9cba1SDylan Hung } 618*54f9cba1SDylan Hung 619*54f9cba1SDylan Hung static void ast2600_init_rmii_clk(struct ast2600_scu *scu, int index) 620*54f9cba1SDylan Hung { 621*54f9cba1SDylan Hung debug("%s not ready\n", __func__); 622*54f9cba1SDylan Hung } 623*54f9cba1SDylan Hung #endif 624f9aa0ee1Sryan_chen static u32 ast2600_configure_mac(struct ast2600_scu *scu, int index) 625f9aa0ee1Sryan_chen { 626f9aa0ee1Sryan_chen u32 reset_bit; 627f9aa0ee1Sryan_chen u32 clkstop_bit; 628f9aa0ee1Sryan_chen 629cc476ffcSDylan Hung if (index < 3) 630cc476ffcSDylan Hung ast2600_configure_mac12_clk(scu); 631cc476ffcSDylan Hung else 632cc476ffcSDylan Hung ast2600_configure_mac34_clk(scu); 633f9aa0ee1Sryan_chen 634f9aa0ee1Sryan_chen switch (index) { 635f9aa0ee1Sryan_chen case 1: 636f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC1); 637f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC1); 638f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl1); 639f9aa0ee1Sryan_chen udelay(100); 640f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 641f9aa0ee1Sryan_chen mdelay(10); 642f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 643f9aa0ee1Sryan_chen 644f9aa0ee1Sryan_chen break; 645f9aa0ee1Sryan_chen case 2: 646f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC2); 647f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC2); 648f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl1); 649f9aa0ee1Sryan_chen udelay(100); 650f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 651f9aa0ee1Sryan_chen mdelay(10); 652f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 653f9aa0ee1Sryan_chen break; 654f9aa0ee1Sryan_chen case 3: 655f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC3 - 32); 656f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC3); 657f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 658f9aa0ee1Sryan_chen udelay(100); 659f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 660f9aa0ee1Sryan_chen mdelay(10); 661f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 662f9aa0ee1Sryan_chen break; 663f9aa0ee1Sryan_chen case 4: 664f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC4 - 32); 665f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC4); 666f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 667f9aa0ee1Sryan_chen udelay(100); 668f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 669f9aa0ee1Sryan_chen mdelay(10); 670f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 671f9aa0ee1Sryan_chen break; 672f9aa0ee1Sryan_chen default: 673f9aa0ee1Sryan_chen return -EINVAL; 674f9aa0ee1Sryan_chen } 675f9aa0ee1Sryan_chen 676f9aa0ee1Sryan_chen return 0; 677f9aa0ee1Sryan_chen } 678550e691bSryan_chen 679f51926eeSryan_chen #define SCU_CLKSTOP_SDIO 4 680f51926eeSryan_chen static ulong ast2600_enable_sdclk(struct ast2600_scu *scu) 681f51926eeSryan_chen { 682f51926eeSryan_chen u32 reset_bit; 683f51926eeSryan_chen u32 clkstop_bit; 684f51926eeSryan_chen 685f51926eeSryan_chen reset_bit = BIT(ASPEED_RESET_SD - 32); 686f51926eeSryan_chen clkstop_bit = BIT(SCU_CLKSTOP_SDIO); 687f51926eeSryan_chen 688f51926eeSryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 689f51926eeSryan_chen udelay(100); 690f51926eeSryan_chen //enable clk 691f51926eeSryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 692f51926eeSryan_chen mdelay(10); 693f51926eeSryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 694f51926eeSryan_chen 695f51926eeSryan_chen return 0; 696f51926eeSryan_chen } 697f51926eeSryan_chen 698f51926eeSryan_chen #define SCU_CLKSTOP_EXTSD 31 699f51926eeSryan_chen #define SCU_CLK_SD_MASK (0x7 << 28) 700f51926eeSryan_chen #define SCU_CLK_SD_DIV(x) (x << 28) 701f51926eeSryan_chen 702f51926eeSryan_chen static ulong ast2600_enable_extsdclk(struct ast2600_scu *scu) 703f51926eeSryan_chen { 704f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel4); 705f51926eeSryan_chen u32 enableclk_bit; 706f51926eeSryan_chen 707f51926eeSryan_chen enableclk_bit = BIT(SCU_CLKSTOP_EXTSD); 708f51926eeSryan_chen 709f51926eeSryan_chen clk_sel &= ~SCU_CLK_SD_MASK; 710f51926eeSryan_chen clk_sel |= SCU_CLK_SD_DIV(0); 711f51926eeSryan_chen writel(clk_sel, &scu->clk_sel4); 712f51926eeSryan_chen 713f51926eeSryan_chen //enable clk 714f51926eeSryan_chen setbits_le32(&scu->clk_sel4, enableclk_bit); 715f51926eeSryan_chen 716f51926eeSryan_chen return 0; 717f51926eeSryan_chen } 718f51926eeSryan_chen 719f51926eeSryan_chen #define SCU_CLKSTOP_EMMC 27 720f51926eeSryan_chen static ulong ast2600_enable_emmcclk(struct ast2600_scu *scu) 721f51926eeSryan_chen { 722f51926eeSryan_chen u32 reset_bit; 723f51926eeSryan_chen u32 clkstop_bit; 724f51926eeSryan_chen 725f51926eeSryan_chen reset_bit = BIT(ASPEED_RESET_EMMC); 726f51926eeSryan_chen clkstop_bit = BIT(SCU_CLKSTOP_EMMC); 727f51926eeSryan_chen 728f51926eeSryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 729f51926eeSryan_chen udelay(100); 730f51926eeSryan_chen //enable clk 731f51926eeSryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 732f51926eeSryan_chen mdelay(10); 733f51926eeSryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 734f51926eeSryan_chen 735f51926eeSryan_chen return 0; 736f51926eeSryan_chen } 737f51926eeSryan_chen 738f51926eeSryan_chen #define SCU_CLKSTOP_EXTEMMC 15 739f51926eeSryan_chen #define SCU_CLK_EMMC_MASK (0x7 << 12) 740f51926eeSryan_chen #define SCU_CLK_EMMC_DIV(x) (x << 12) 741f51926eeSryan_chen 742f51926eeSryan_chen static ulong ast2600_enable_extemmcclk(struct ast2600_scu *scu) 743f51926eeSryan_chen { 744f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel1); 745f51926eeSryan_chen u32 enableclk_bit; 746f51926eeSryan_chen 747f51926eeSryan_chen enableclk_bit = BIT(SCU_CLKSTOP_EXTSD); 748f51926eeSryan_chen 749f51926eeSryan_chen clk_sel &= ~SCU_CLK_SD_MASK; 750f51926eeSryan_chen clk_sel |= SCU_CLK_SD_DIV(1); 751f51926eeSryan_chen writel(clk_sel, &scu->clk_sel1); 752f51926eeSryan_chen 753f51926eeSryan_chen //enable clk 754f51926eeSryan_chen setbits_le32(&scu->clk_sel1, enableclk_bit); 755f51926eeSryan_chen 756f51926eeSryan_chen return 0; 757f51926eeSryan_chen } 758f51926eeSryan_chen 759d6e349c7Sryan_chen static int ast2600_clk_enable(struct clk *clk) 760550e691bSryan_chen { 761f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 762550e691bSryan_chen 763550e691bSryan_chen switch (clk->id) { 76486f91560Sryan_chen case ASPEED_CLK_GATE_MAC1CLK: 76586f91560Sryan_chen ast2600_configure_mac(priv->scu, 1); 766550e691bSryan_chen break; 76786f91560Sryan_chen case ASPEED_CLK_GATE_MAC2CLK: 76886f91560Sryan_chen ast2600_configure_mac(priv->scu, 2); 769550e691bSryan_chen break; 77077843939Sryan_chen case ASPEED_CLK_GATE_MAC3CLK: 77177843939Sryan_chen ast2600_configure_mac(priv->scu, 3); 77277843939Sryan_chen break; 77377843939Sryan_chen case ASPEED_CLK_GATE_MAC4CLK: 77477843939Sryan_chen ast2600_configure_mac(priv->scu, 4); 77577843939Sryan_chen break; 776f51926eeSryan_chen case ASPEED_CLK_GATE_SDCLK: 777f51926eeSryan_chen ast2600_enable_sdclk(priv->scu); 778f51926eeSryan_chen break; 779f51926eeSryan_chen case ASPEED_CLK_GATE_SDEXTCLK: 780f51926eeSryan_chen ast2600_enable_extsdclk(priv->scu); 781f51926eeSryan_chen break; 782f51926eeSryan_chen case ASPEED_CLK_GATE_EMMCCLK: 783f51926eeSryan_chen ast2600_enable_emmcclk(priv->scu); 784f51926eeSryan_chen break; 785f51926eeSryan_chen case ASPEED_CLK_GATE_EMMCEXTCLK: 786f51926eeSryan_chen ast2600_enable_extemmcclk(priv->scu); 787f51926eeSryan_chen break; 788550e691bSryan_chen default: 789f9aa0ee1Sryan_chen pr_debug("can't enable clk \n"); 790550e691bSryan_chen return -ENOENT; 79177843939Sryan_chen break; 792550e691bSryan_chen } 793550e691bSryan_chen 794550e691bSryan_chen return 0; 795550e691bSryan_chen } 796550e691bSryan_chen 797f9aa0ee1Sryan_chen struct clk_ops ast2600_clk_ops = { 798d6e349c7Sryan_chen .get_rate = ast2600_clk_get_rate, 799d6e349c7Sryan_chen .set_rate = ast2600_clk_set_rate, 800d6e349c7Sryan_chen .enable = ast2600_clk_enable, 801550e691bSryan_chen }; 802550e691bSryan_chen 803d6e349c7Sryan_chen static int ast2600_clk_probe(struct udevice *dev) 804550e691bSryan_chen { 805f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(dev); 806550e691bSryan_chen 807f0d895afSryan_chen priv->scu = devfdt_get_addr_ptr(dev); 808f0d895afSryan_chen if (IS_ERR(priv->scu)) 809f0d895afSryan_chen return PTR_ERR(priv->scu); 810550e691bSryan_chen 811550e691bSryan_chen return 0; 812550e691bSryan_chen } 813550e691bSryan_chen 814d6e349c7Sryan_chen static int ast2600_clk_bind(struct udevice *dev) 815550e691bSryan_chen { 816550e691bSryan_chen int ret; 817550e691bSryan_chen 818550e691bSryan_chen /* The reset driver does not have a device node, so bind it here */ 819550e691bSryan_chen ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev); 820550e691bSryan_chen if (ret) 821550e691bSryan_chen debug("Warning: No reset driver: ret=%d\n", ret); 822550e691bSryan_chen 823550e691bSryan_chen return 0; 824550e691bSryan_chen } 825550e691bSryan_chen 826d35ac78cSryan_chen #if CONFIG_IS_ENABLED(CMD_CLK) 827d35ac78cSryan_chen struct aspeed_clks { 828d35ac78cSryan_chen ulong id; 829d35ac78cSryan_chen const char *name; 830d35ac78cSryan_chen }; 831d35ac78cSryan_chen 832d35ac78cSryan_chen static struct aspeed_clks aspeed_clk_names[] = { 833d35ac78cSryan_chen { ASPEED_CLK_HPLL, "hpll" }, 834d35ac78cSryan_chen { ASPEED_CLK_MPLL, "mpll" }, 835d35ac78cSryan_chen { ASPEED_CLK_APLL, "apll" }, 836d35ac78cSryan_chen { ASPEED_CLK_EPLL, "epll" }, 837d35ac78cSryan_chen { ASPEED_CLK_DPLL, "dpll" }, 838d35ac78cSryan_chen { ASPEED_CLK_AHB, "hclk" }, 839d35ac78cSryan_chen { ASPEED_CLK_APB, "pclk" }, 840d35ac78cSryan_chen }; 841d35ac78cSryan_chen 842d35ac78cSryan_chen int soc_clk_dump(void) 843d35ac78cSryan_chen { 844d35ac78cSryan_chen struct udevice *dev; 845d35ac78cSryan_chen struct clk clk; 846d35ac78cSryan_chen unsigned long rate; 847d35ac78cSryan_chen int i, ret; 848d35ac78cSryan_chen 849d35ac78cSryan_chen ret = uclass_get_device_by_driver(UCLASS_CLK, 850d35ac78cSryan_chen DM_GET_DRIVER(aspeed_scu), &dev); 851d35ac78cSryan_chen if (ret) 852d35ac78cSryan_chen return ret; 853d35ac78cSryan_chen 854d35ac78cSryan_chen printf("Clk\t\tHz\n"); 855d35ac78cSryan_chen 856d35ac78cSryan_chen for (i = 0; i < ARRAY_SIZE(aspeed_clk_names); i++) { 857d35ac78cSryan_chen clk.id = aspeed_clk_names[i].id; 858d35ac78cSryan_chen ret = clk_request(dev, &clk); 859d35ac78cSryan_chen if (ret < 0) { 860d35ac78cSryan_chen debug("%s clk_request() failed: %d\n", __func__, ret); 861d35ac78cSryan_chen continue; 862d35ac78cSryan_chen } 863d35ac78cSryan_chen 864d35ac78cSryan_chen ret = clk_get_rate(&clk); 865d35ac78cSryan_chen rate = ret; 866d35ac78cSryan_chen 867d35ac78cSryan_chen clk_free(&clk); 868d35ac78cSryan_chen 869d35ac78cSryan_chen if (ret == -ENOTSUPP) { 870d35ac78cSryan_chen printf("clk ID %lu not supported yet\n", 871d35ac78cSryan_chen aspeed_clk_names[i].id); 872d35ac78cSryan_chen continue; 873d35ac78cSryan_chen } 874d35ac78cSryan_chen if (ret < 0) { 875d35ac78cSryan_chen printf("%s %lu: get_rate err: %d\n", 876d35ac78cSryan_chen __func__, aspeed_clk_names[i].id, ret); 877d35ac78cSryan_chen continue; 878d35ac78cSryan_chen } 879d35ac78cSryan_chen 880d35ac78cSryan_chen printf("%s(%3lu):\t%lu\n", 881d35ac78cSryan_chen aspeed_clk_names[i].name, aspeed_clk_names[i].id, rate); 882d35ac78cSryan_chen } 883d35ac78cSryan_chen 884d35ac78cSryan_chen return 0; 885d35ac78cSryan_chen } 886d35ac78cSryan_chen #endif 887d35ac78cSryan_chen 888d6e349c7Sryan_chen static const struct udevice_id ast2600_clk_ids[] = { 889d6e349c7Sryan_chen { .compatible = "aspeed,ast2600-scu", }, 890550e691bSryan_chen { } 891550e691bSryan_chen }; 892550e691bSryan_chen 893aa36597fSDylan Hung U_BOOT_DRIVER(aspeed_scu) = { 894aa36597fSDylan Hung .name = "aspeed_scu", 895550e691bSryan_chen .id = UCLASS_CLK, 896d6e349c7Sryan_chen .of_match = ast2600_clk_ids, 897f0d895afSryan_chen .priv_auto_alloc_size = sizeof(struct ast2600_clk_priv), 898f9aa0ee1Sryan_chen .ops = &ast2600_clk_ops, 899d6e349c7Sryan_chen .bind = ast2600_clk_bind, 900d6e349c7Sryan_chen .probe = ast2600_clk_probe, 901550e691bSryan_chen }; 902