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 50550e691bSryan_chen /* 51550e691bSryan_chen * Get the rate of the M-PLL clock from input clock frequency and 52550e691bSryan_chen * the value of the M-PLL Parameter Register. 53550e691bSryan_chen */ 544f22e838Sryan_chen extern u32 ast2600_get_mpll_rate(struct ast2600_scu *scu) 55550e691bSryan_chen { 56d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 5739283ea7Sryan_chen u32 mpll_reg = readl(&scu->m_pll_param); 589639db61Sryan_chen unsigned int mult, div = 1; 59550e691bSryan_chen 609639db61Sryan_chen if (mpll_reg & BIT(24)) { 619639db61Sryan_chen /* Pass through mode */ 629639db61Sryan_chen mult = div = 1; 639639db61Sryan_chen } else { 649639db61Sryan_chen /* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1) */ 659639db61Sryan_chen u32 m = mpll_reg & 0x1fff; 669639db61Sryan_chen u32 n = (mpll_reg >> 13) & 0x3f; 679639db61Sryan_chen u32 p = (mpll_reg >> 19) & 0xf; 689639db61Sryan_chen mult = (m + 1) / (n + 1); 699639db61Sryan_chen div = (p + 1); 709639db61Sryan_chen } 719639db61Sryan_chen return ((clkin * mult)/div); 72550e691bSryan_chen 73550e691bSryan_chen } 74550e691bSryan_chen 75550e691bSryan_chen /* 76550e691bSryan_chen * Get the rate of the H-PLL clock from input clock frequency and 77550e691bSryan_chen * the value of the H-PLL Parameter Register. 78550e691bSryan_chen */ 794f22e838Sryan_chen extern u32 ast2600_get_hpll_rate(struct ast2600_scu *scu) 80550e691bSryan_chen { 814f22e838Sryan_chen u32 clkin = AST2600_CLK_IN; 8239283ea7Sryan_chen u32 hpll_reg = readl(&scu->h_pll_param); 834f22e838Sryan_chen unsigned int mult, div = 1; 84f0d895afSryan_chen 854f22e838Sryan_chen if (hpll_reg & BIT(24)) { 864f22e838Sryan_chen /* Pass through mode */ 874f22e838Sryan_chen mult = div = 1; 884f22e838Sryan_chen } else { 894f22e838Sryan_chen /* F = 25Mhz * [(M + 1) / (n + 1)] / (p + 1) */ 904f22e838Sryan_chen u32 m = (hpll_reg & 0x1fff); 914f22e838Sryan_chen u32 n = (hpll_reg >> 13) & 0x3f; 924f22e838Sryan_chen u32 p = (hpll_reg >> 19) & 0xf; 934f22e838Sryan_chen mult = (m + 1) / (n + 1); 944f22e838Sryan_chen div = (p + 1); 954f22e838Sryan_chen } 964f22e838Sryan_chen return ((clkin * mult)/div); 97550e691bSryan_chen } 98550e691bSryan_chen 99f9aa0ee1Sryan_chen extern u32 ast2600_get_dpll_rate(struct ast2600_scu *scu) 100f9aa0ee1Sryan_chen { 101f9aa0ee1Sryan_chen u32 clk_in = AST2600_CLK_IN; 102f9aa0ee1Sryan_chen u32 dpll_reg = readl(&scu->d_pll_param); 103f9aa0ee1Sryan_chen unsigned int mult, div = 1; 104f9aa0ee1Sryan_chen 105f9aa0ee1Sryan_chen if (dpll_reg & BIT(24)) { 106f9aa0ee1Sryan_chen /* Pass through mode */ 107f9aa0ee1Sryan_chen mult = div = 1; 108f9aa0ee1Sryan_chen } else { 109f9aa0ee1Sryan_chen /* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1)*/ 110f9aa0ee1Sryan_chen u32 m = dpll_reg & 0x1fff; 111f9aa0ee1Sryan_chen u32 n = (dpll_reg >> 13) & 0x3f; 112f9aa0ee1Sryan_chen u32 p = (dpll_reg >> 19) & 0x7; 113f9aa0ee1Sryan_chen mult = ((m + 1) / (n + 1)); 114f9aa0ee1Sryan_chen div = (p + 1); 115f9aa0ee1Sryan_chen } 116f9aa0ee1Sryan_chen return (clk_in * mult)/div; 117f9aa0ee1Sryan_chen } 118f9aa0ee1Sryan_chen 1194f22e838Sryan_chen extern u32 ast2600_get_apll_rate(struct ast2600_scu *scu) 120550e691bSryan_chen { 12139283ea7Sryan_chen u32 clk_in = AST2600_CLK_IN; 12239283ea7Sryan_chen u32 apll_reg = readl(&scu->a_pll_param); 12339283ea7Sryan_chen unsigned int mult, div = 1; 124d6e349c7Sryan_chen 12539283ea7Sryan_chen if (apll_reg & BIT(20)) { 126d6e349c7Sryan_chen /* Pass through mode */ 127d6e349c7Sryan_chen mult = div = 1; 128d6e349c7Sryan_chen } else { 129d6e349c7Sryan_chen /* F = 25Mhz * (2-OD) * [(M + 2) / (n + 1)] */ 13039283ea7Sryan_chen u32 m = (apll_reg >> 5) & 0x3f; 13139283ea7Sryan_chen u32 od = (apll_reg >> 4) & 0x1; 13239283ea7Sryan_chen u32 n = apll_reg & 0xf; 133d6e349c7Sryan_chen 13439283ea7Sryan_chen mult = (2 - od) * ((m + 2) / (n + 1)); 135d6e349c7Sryan_chen } 136d6e349c7Sryan_chen return (clk_in * mult)/div; 137d6e349c7Sryan_chen } 138d6e349c7Sryan_chen 1394f22e838Sryan_chen extern u32 ast2600_get_epll_rate(struct ast2600_scu *scu) 14039283ea7Sryan_chen { 14139283ea7Sryan_chen u32 clk_in = AST2600_CLK_IN; 14239283ea7Sryan_chen u32 epll_reg = readl(&scu->e_pll_param); 14339283ea7Sryan_chen unsigned int mult, div = 1; 14439283ea7Sryan_chen 14539283ea7Sryan_chen if (epll_reg & BIT(24)) { 14639283ea7Sryan_chen /* Pass through mode */ 14739283ea7Sryan_chen mult = div = 1; 14839283ea7Sryan_chen } else { 14939283ea7Sryan_chen /* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1)*/ 15039283ea7Sryan_chen u32 m = epll_reg & 0x1fff; 15139283ea7Sryan_chen u32 n = (epll_reg >> 13) & 0x3f; 15239283ea7Sryan_chen u32 p = (epll_reg >> 19) & 0x7; 15339283ea7Sryan_chen 15439283ea7Sryan_chen mult = ((m + 1) / (n + 1)); 15539283ea7Sryan_chen div = (p + 1); 15639283ea7Sryan_chen } 15739283ea7Sryan_chen return (clk_in * mult)/div; 15839283ea7Sryan_chen } 15939283ea7Sryan_chen 160d812df15Sryan_chen static u32 ast2600_a0_axi_ahb_div_table[] = { 161d812df15Sryan_chen 2, 2, 3, 5, 162d812df15Sryan_chen }; 163d812df15Sryan_chen 164d812df15Sryan_chen static u32 ast2600_a1_axi_ahb_div_table[] = { 165d812df15Sryan_chen 4, 6, 2, 4, 166d812df15Sryan_chen }; 167d812df15Sryan_chen 168d812df15Sryan_chen static u32 ast2600_get_hclk(struct ast2600_scu *scu) 169d812df15Sryan_chen { 170d812df15Sryan_chen u32 hw_rev = readl(&scu->chip_id0); 171d812df15Sryan_chen u32 hwstrap1 = readl(&scu->hwstrap1); 172d812df15Sryan_chen u32 axi_div = 1; 173d812df15Sryan_chen u32 ahb_div = 0; 174d812df15Sryan_chen u32 rate = 0; 175d812df15Sryan_chen 176d812df15Sryan_chen if((hwstrap1 >> 16) & 0x1) 177d812df15Sryan_chen axi_div = 1; 178d812df15Sryan_chen else 179d812df15Sryan_chen axi_div = 2; 180d812df15Sryan_chen 181d812df15Sryan_chen if (hw_rev & BIT(16)) 182d812df15Sryan_chen ahb_div = ast2600_a1_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 183d812df15Sryan_chen else 184d812df15Sryan_chen ahb_div = ast2600_a0_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 185d812df15Sryan_chen 186d812df15Sryan_chen rate = ast2600_get_hpll_rate(scu); 187d812df15Sryan_chen 1882717883aSryan_chen return (rate / axi_div / ahb_div); 1892717883aSryan_chen } 1902717883aSryan_chen 1912717883aSryan_chen static u32 ast2600_hpll_pclk_div_table[] = { 1922717883aSryan_chen 4, 8, 12, 16, 20, 24, 28, 32, 1932717883aSryan_chen }; 1942717883aSryan_chen 1952717883aSryan_chen static u32 ast2600_get_pclk(struct ast2600_scu *scu) 1962717883aSryan_chen { 1972717883aSryan_chen u32 clk_sel1 = readl(&scu->clk_sel1); 1982717883aSryan_chen u32 apb_div = ast2600_hpll_pclk_div_table[((clk_sel1 >> 23) & 0x7)]; 1992717883aSryan_chen u32 rate = ast2600_get_hpll_rate(scu); 2002717883aSryan_chen 2012717883aSryan_chen return (rate / apb_div); 202d812df15Sryan_chen } 203d812df15Sryan_chen 204d6e349c7Sryan_chen 20527881d20Sryan_chen static u32 ast2600_get_uxclk_rate(struct ast2600_scu *scu) 206d6e349c7Sryan_chen { 20727881d20Sryan_chen u32 clk_in = 0; 20827881d20Sryan_chen u32 uxclk_sel = readl(&scu->clk_sel4); 209550e691bSryan_chen 21027881d20Sryan_chen uxclk_sel &= 0x3; 21127881d20Sryan_chen switch(uxclk_sel) { 21227881d20Sryan_chen case 0: 21327881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 4; 21427881d20Sryan_chen break; 21527881d20Sryan_chen case 1: 21627881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 2; 21727881d20Sryan_chen break; 21827881d20Sryan_chen case 2: 21927881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu); 22027881d20Sryan_chen break; 22127881d20Sryan_chen case 3: 22227881d20Sryan_chen clk_in = ast2600_get_hclk(scu); 22327881d20Sryan_chen break; 22427881d20Sryan_chen } 225d6e349c7Sryan_chen 22627881d20Sryan_chen return clk_in; 22727881d20Sryan_chen } 22827881d20Sryan_chen 22927881d20Sryan_chen static u32 ast2600_get_huxclk_rate(struct ast2600_scu *scu) 23027881d20Sryan_chen { 23127881d20Sryan_chen u32 clk_in = 0; 23227881d20Sryan_chen u32 huclk_sel = readl(&scu->clk_sel4); 23327881d20Sryan_chen 23427881d20Sryan_chen huclk_sel = ((huclk_sel >> 3) & 0x3); 23527881d20Sryan_chen switch(huclk_sel) { 23627881d20Sryan_chen case 0: 23727881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 4; 23827881d20Sryan_chen break; 23927881d20Sryan_chen case 1: 24027881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 2; 24127881d20Sryan_chen break; 24227881d20Sryan_chen case 2: 24327881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu); 24427881d20Sryan_chen break; 24527881d20Sryan_chen case 3: 24627881d20Sryan_chen clk_in = ast2600_get_hclk(scu); 24727881d20Sryan_chen break; 24827881d20Sryan_chen } 24927881d20Sryan_chen 25027881d20Sryan_chen return clk_in; 25127881d20Sryan_chen } 25227881d20Sryan_chen 25327881d20Sryan_chen static u32 ast2600_get_uart_from_uxclk_rate(struct ast2600_scu *scu) 25427881d20Sryan_chen { 25527881d20Sryan_chen u32 clk_in = ast2600_get_uxclk_rate(scu); 25627881d20Sryan_chen u32 div_reg = readl(&scu->uart_24m_ref_uxclk); 25727881d20Sryan_chen unsigned int mult, div; 25827881d20Sryan_chen 25927881d20Sryan_chen u32 n = (div_reg >> 8) & 0x3ff; 26027881d20Sryan_chen u32 r = div_reg & 0xff; 26127881d20Sryan_chen 26227881d20Sryan_chen mult = r; 26327881d20Sryan_chen div = (n * 4); 26427881d20Sryan_chen return (clk_in * mult)/div; 26527881d20Sryan_chen } 26627881d20Sryan_chen 26727881d20Sryan_chen static u32 ast2600_get_uart_from_huxclk_rate(struct ast2600_scu *scu) 26827881d20Sryan_chen { 26927881d20Sryan_chen u32 clk_in = ast2600_get_huxclk_rate(scu); 27027881d20Sryan_chen u32 div_reg = readl(&scu->uart_24m_ref_huxclk); 27127881d20Sryan_chen 27227881d20Sryan_chen unsigned int mult, div; 27327881d20Sryan_chen 27427881d20Sryan_chen u32 n = (div_reg >> 8) & 0x3ff; 27527881d20Sryan_chen u32 r = div_reg & 0xff; 27627881d20Sryan_chen 27727881d20Sryan_chen mult = r; 27827881d20Sryan_chen div = (n * 4); 27927881d20Sryan_chen return (clk_in * mult)/div; 28027881d20Sryan_chen } 28127881d20Sryan_chen 282*f51926eeSryan_chen static u32 ast2600_get_sdio_clk_rate(struct ast2600_scu *scu) 283*f51926eeSryan_chen { 284*f51926eeSryan_chen u32 clkin = 0; 285*f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel4); 286*f51926eeSryan_chen u32 div = (clk_sel >> 28) & 0x7; 287*f51926eeSryan_chen 288*f51926eeSryan_chen if(clk_sel & BIT(8)) { 289*f51926eeSryan_chen clkin = ast2600_get_apll_rate(scu); 290*f51926eeSryan_chen } else { 291*f51926eeSryan_chen clkin = 200 * 1000 * 1000; 292*f51926eeSryan_chen } 293*f51926eeSryan_chen div = (div + 1) << 1; 294*f51926eeSryan_chen 295*f51926eeSryan_chen return (clkin / div); 296*f51926eeSryan_chen } 297*f51926eeSryan_chen 298*f51926eeSryan_chen static u32 ast2600_get_emmc_clk_rate(struct ast2600_scu *scu) 299*f51926eeSryan_chen { 300*f51926eeSryan_chen u32 clkin = ast2600_get_hpll_rate(scu); 301*f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel1); 302*f51926eeSryan_chen u32 div = (clk_sel >> 12) & 0x7; 303*f51926eeSryan_chen 304*f51926eeSryan_chen div = (div + 1) << 2; 305*f51926eeSryan_chen 306*f51926eeSryan_chen return (clkin / div); 307*f51926eeSryan_chen } 308*f51926eeSryan_chen 309*f51926eeSryan_chen static u32 ast2600_get_uart_clk_rate(struct ast2600_scu *scu, int uart_idx) 31027881d20Sryan_chen { 31127881d20Sryan_chen u32 uart_sel = readl(&scu->clk_sel4); 31227881d20Sryan_chen u32 uart_sel5 = readl(&scu->clk_sel5); 31327881d20Sryan_chen ulong uart_clk = 0; 31427881d20Sryan_chen 31527881d20Sryan_chen switch(uart_idx) { 31627881d20Sryan_chen case 1: 31727881d20Sryan_chen case 2: 31827881d20Sryan_chen case 3: 31927881d20Sryan_chen case 4: 32027881d20Sryan_chen case 6: 32127881d20Sryan_chen if(uart_sel & BIT(uart_idx - 1)) 32227881d20Sryan_chen uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ; 323550e691bSryan_chen else 32427881d20Sryan_chen uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ; 32527881d20Sryan_chen break; 32627881d20Sryan_chen case 5: //24mhz is come form usb phy 48Mhz 32727881d20Sryan_chen { 32827881d20Sryan_chen u8 uart5_clk_sel = 0; 32927881d20Sryan_chen //high bit 33027881d20Sryan_chen if (readl(&scu->misc_ctrl1) & BIT(12)) 33127881d20Sryan_chen uart5_clk_sel = 0x2; 33227881d20Sryan_chen else 33327881d20Sryan_chen uart5_clk_sel = 0x0; 334550e691bSryan_chen 33527881d20Sryan_chen if (readl(&scu->clk_sel2) & BIT(14)) 33627881d20Sryan_chen uart5_clk_sel |= 0x1; 337550e691bSryan_chen 33827881d20Sryan_chen switch(uart5_clk_sel) { 33927881d20Sryan_chen case 0: 34027881d20Sryan_chen uart_clk = 24000000; 34127881d20Sryan_chen break; 34227881d20Sryan_chen case 1: 34327881d20Sryan_chen uart_clk = 0; 34427881d20Sryan_chen break; 34527881d20Sryan_chen case 2: 34627881d20Sryan_chen uart_clk = 24000000/13; 34727881d20Sryan_chen break; 34827881d20Sryan_chen case 3: 34927881d20Sryan_chen uart_clk = 192000000/13; 35027881d20Sryan_chen break; 35127881d20Sryan_chen } 35227881d20Sryan_chen } 35327881d20Sryan_chen break; 35427881d20Sryan_chen case 7: 35527881d20Sryan_chen case 8: 35627881d20Sryan_chen case 9: 35727881d20Sryan_chen case 10: 35827881d20Sryan_chen case 11: 35927881d20Sryan_chen case 12: 36027881d20Sryan_chen case 13: 36127881d20Sryan_chen if(uart_sel5 & BIT(uart_idx - 1)) 36227881d20Sryan_chen uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ; 36327881d20Sryan_chen else 36427881d20Sryan_chen uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ; 36527881d20Sryan_chen break; 36627881d20Sryan_chen } 36727881d20Sryan_chen 36827881d20Sryan_chen return uart_clk; 369550e691bSryan_chen } 370550e691bSryan_chen 371feb42054Sryan_chen static ulong ast2600_clk_get_rate(struct clk *clk) 372feb42054Sryan_chen { 373feb42054Sryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 374feb42054Sryan_chen ulong rate = 0; 375feb42054Sryan_chen 376feb42054Sryan_chen switch (clk->id) { 377feb42054Sryan_chen case ASPEED_CLK_HPLL: 378feb42054Sryan_chen rate = ast2600_get_hpll_rate(priv->scu); 379feb42054Sryan_chen break; 380d812df15Sryan_chen case ASPEED_CLK_MPLL: 381d812df15Sryan_chen rate = ast2600_get_mpll_rate(priv->scu); 382d812df15Sryan_chen break; 383feb42054Sryan_chen case ASPEED_CLK_AHB: 384feb42054Sryan_chen rate = ast2600_get_hclk(priv->scu); 385feb42054Sryan_chen break; 386feb42054Sryan_chen case ASPEED_CLK_APB: 3872717883aSryan_chen rate = ast2600_get_pclk(priv->scu); 388feb42054Sryan_chen break; 389feb42054Sryan_chen case ASPEED_CLK_GATE_UART1CLK: 390feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 1); 391feb42054Sryan_chen break; 392feb42054Sryan_chen case ASPEED_CLK_GATE_UART2CLK: 393feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 2); 394feb42054Sryan_chen break; 395feb42054Sryan_chen case ASPEED_CLK_GATE_UART3CLK: 396feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 3); 397feb42054Sryan_chen break; 398feb42054Sryan_chen case ASPEED_CLK_GATE_UART4CLK: 399feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 4); 400feb42054Sryan_chen break; 401feb42054Sryan_chen case ASPEED_CLK_GATE_UART5CLK: 402feb42054Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 5); 403feb42054Sryan_chen break; 404*f51926eeSryan_chen case ASPEED_CLK_SDIO: 405*f51926eeSryan_chen rate = ast2600_get_sdio_clk_rate(priv->scu); 406*f51926eeSryan_chen break; 407*f51926eeSryan_chen case ASPEED_CLK_EMMC: 408*f51926eeSryan_chen rate = ast2600_get_emmc_clk_rate(priv->scu); 409*f51926eeSryan_chen break; 410feb42054Sryan_chen default: 411d812df15Sryan_chen pr_debug("can't get clk rate \n"); 412feb42054Sryan_chen return -ENOENT; 413d812df15Sryan_chen break; 414feb42054Sryan_chen } 415feb42054Sryan_chen 416feb42054Sryan_chen return rate; 417feb42054Sryan_chen } 418feb42054Sryan_chen 419550e691bSryan_chen struct aspeed_clock_config { 420550e691bSryan_chen ulong input_rate; 421550e691bSryan_chen ulong rate; 42239283ea7Sryan_chen struct ast2600_div_config cfg; 423550e691bSryan_chen }; 424550e691bSryan_chen 425550e691bSryan_chen static const struct aspeed_clock_config aspeed_clock_config_defaults[] = { 4261cd71a14SDylan Hung { 25000000, 400000000, { .num = 95, .denum = 2, .post_div = 1 } }, 427550e691bSryan_chen }; 428550e691bSryan_chen 429550e691bSryan_chen static bool aspeed_get_clock_config_default(ulong input_rate, 430550e691bSryan_chen ulong requested_rate, 43139283ea7Sryan_chen struct ast2600_div_config *cfg) 432550e691bSryan_chen { 433550e691bSryan_chen int i; 434550e691bSryan_chen 435550e691bSryan_chen for (i = 0; i < ARRAY_SIZE(aspeed_clock_config_defaults); i++) { 436550e691bSryan_chen const struct aspeed_clock_config *default_cfg = 437550e691bSryan_chen &aspeed_clock_config_defaults[i]; 438550e691bSryan_chen if (default_cfg->input_rate == input_rate && 439550e691bSryan_chen default_cfg->rate == requested_rate) { 440550e691bSryan_chen *cfg = default_cfg->cfg; 441550e691bSryan_chen return true; 442550e691bSryan_chen } 443550e691bSryan_chen } 444550e691bSryan_chen 445550e691bSryan_chen return false; 446550e691bSryan_chen } 447550e691bSryan_chen 448550e691bSryan_chen /* 449550e691bSryan_chen * @input_rate - the rate of input clock in Hz 450550e691bSryan_chen * @requested_rate - desired output rate in Hz 451550e691bSryan_chen * @div - this is an IN/OUT parameter, at input all fields of the config 452550e691bSryan_chen * need to be set to their maximum allowed values. 453550e691bSryan_chen * The result (the best config we could find), would also be returned 454550e691bSryan_chen * in this structure. 455550e691bSryan_chen * 456550e691bSryan_chen * @return The clock rate, when the resulting div_config is used. 457550e691bSryan_chen */ 458550e691bSryan_chen static ulong aspeed_calc_clock_config(ulong input_rate, ulong requested_rate, 45939283ea7Sryan_chen struct ast2600_div_config *cfg) 460550e691bSryan_chen { 461550e691bSryan_chen /* 462550e691bSryan_chen * The assumption is that kHz precision is good enough and 463550e691bSryan_chen * also enough to avoid overflow when multiplying. 464550e691bSryan_chen */ 465550e691bSryan_chen const ulong input_rate_khz = input_rate / 1000; 466550e691bSryan_chen const ulong rate_khz = requested_rate / 1000; 46739283ea7Sryan_chen const struct ast2600_div_config max_vals = *cfg; 46839283ea7Sryan_chen struct ast2600_div_config it = { 0, 0, 0 }; 469550e691bSryan_chen ulong delta = rate_khz; 470550e691bSryan_chen ulong new_rate_khz = 0; 471550e691bSryan_chen 472550e691bSryan_chen /* 473550e691bSryan_chen * Look for a well known frequency first. 474550e691bSryan_chen */ 475550e691bSryan_chen if (aspeed_get_clock_config_default(input_rate, requested_rate, cfg)) 476550e691bSryan_chen return requested_rate; 477550e691bSryan_chen 478550e691bSryan_chen for (; it.denum <= max_vals.denum; ++it.denum) { 479550e691bSryan_chen for (it.post_div = 0; it.post_div <= max_vals.post_div; 480550e691bSryan_chen ++it.post_div) { 481550e691bSryan_chen it.num = (rate_khz * (it.post_div + 1) / input_rate_khz) 482550e691bSryan_chen * (it.denum + 1); 483550e691bSryan_chen if (it.num > max_vals.num) 484550e691bSryan_chen continue; 485550e691bSryan_chen 486550e691bSryan_chen new_rate_khz = (input_rate_khz 487550e691bSryan_chen * ((it.num + 1) / (it.denum + 1))) 488550e691bSryan_chen / (it.post_div + 1); 489550e691bSryan_chen 490550e691bSryan_chen /* Keep the rate below requested one. */ 491550e691bSryan_chen if (new_rate_khz > rate_khz) 492550e691bSryan_chen continue; 493550e691bSryan_chen 494550e691bSryan_chen if (new_rate_khz - rate_khz < delta) { 495550e691bSryan_chen delta = new_rate_khz - rate_khz; 496550e691bSryan_chen *cfg = it; 497550e691bSryan_chen if (delta == 0) 498550e691bSryan_chen return new_rate_khz * 1000; 499550e691bSryan_chen } 500550e691bSryan_chen } 501550e691bSryan_chen } 502550e691bSryan_chen 503550e691bSryan_chen return new_rate_khz * 1000; 504550e691bSryan_chen } 505550e691bSryan_chen 506feb42054Sryan_chen static u32 ast2600_configure_ddr(struct ast2600_scu *scu, ulong rate) 507550e691bSryan_chen { 508d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 509550e691bSryan_chen u32 mpll_reg; 51039283ea7Sryan_chen struct ast2600_div_config div_cfg = { 511550e691bSryan_chen .num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT), 512550e691bSryan_chen .denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT), 513550e691bSryan_chen .post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT), 514550e691bSryan_chen }; 515550e691bSryan_chen 516550e691bSryan_chen aspeed_calc_clock_config(clkin, rate, &div_cfg); 517550e691bSryan_chen 518feb42054Sryan_chen mpll_reg = readl(&scu->m_pll_param); 519550e691bSryan_chen mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK 520550e691bSryan_chen | SCU_MPLL_DENUM_MASK); 521550e691bSryan_chen mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT) 522550e691bSryan_chen | (div_cfg.num << SCU_MPLL_NUM_SHIFT) 523550e691bSryan_chen | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT); 524550e691bSryan_chen 525feb42054Sryan_chen writel(mpll_reg, &scu->m_pll_param); 526550e691bSryan_chen 527feb42054Sryan_chen return ast2600_get_mpll_rate(scu); 528d6e349c7Sryan_chen } 529d6e349c7Sryan_chen 530d6e349c7Sryan_chen static ulong ast2600_clk_set_rate(struct clk *clk, ulong rate) 531550e691bSryan_chen { 532f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 533550e691bSryan_chen 534550e691bSryan_chen ulong new_rate; 535550e691bSryan_chen switch (clk->id) { 536f0d895afSryan_chen case ASPEED_CLK_MPLL: 537feb42054Sryan_chen new_rate = ast2600_configure_ddr(priv->scu, rate); 538550e691bSryan_chen break; 539550e691bSryan_chen default: 540550e691bSryan_chen return -ENOENT; 541550e691bSryan_chen } 542550e691bSryan_chen 543550e691bSryan_chen return new_rate; 544550e691bSryan_chen } 545feb42054Sryan_chen 546f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC1 (20) 547f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC2 (21) 548f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC3 (20) 549f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC4 (21) 550f9aa0ee1Sryan_chen 551f9aa0ee1Sryan_chen static u32 ast2600_configure_mac(struct ast2600_scu *scu, int index) 552f9aa0ee1Sryan_chen { 553f9aa0ee1Sryan_chen u32 reset_bit; 554f9aa0ee1Sryan_chen u32 clkstop_bit; 555f9aa0ee1Sryan_chen 556f9aa0ee1Sryan_chen 557f9aa0ee1Sryan_chen switch (index) { 558f9aa0ee1Sryan_chen case 1: 559f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC1); 560f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC1); 561f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl1); 562f9aa0ee1Sryan_chen udelay(100); 563f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 564f9aa0ee1Sryan_chen mdelay(10); 565f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 566f9aa0ee1Sryan_chen 567f9aa0ee1Sryan_chen break; 568f9aa0ee1Sryan_chen case 2: 569f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC2); 570f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC2); 571f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl1); 572f9aa0ee1Sryan_chen udelay(100); 573f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 574f9aa0ee1Sryan_chen mdelay(10); 575f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 576f9aa0ee1Sryan_chen break; 577f9aa0ee1Sryan_chen case 3: 578f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC3 - 32); 579f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC3); 580f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 581f9aa0ee1Sryan_chen udelay(100); 582f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 583f9aa0ee1Sryan_chen mdelay(10); 584f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 585f9aa0ee1Sryan_chen break; 586f9aa0ee1Sryan_chen case 4: 587f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC4 - 32); 588f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC4); 589f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 590f9aa0ee1Sryan_chen udelay(100); 591f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 592f9aa0ee1Sryan_chen mdelay(10); 593f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 594f9aa0ee1Sryan_chen break; 595f9aa0ee1Sryan_chen default: 596f9aa0ee1Sryan_chen return -EINVAL; 597f9aa0ee1Sryan_chen } 598f9aa0ee1Sryan_chen 599f9aa0ee1Sryan_chen return 0; 600f9aa0ee1Sryan_chen } 601550e691bSryan_chen 602*f51926eeSryan_chen #define SCU_CLKSTOP_SDIO 4 603*f51926eeSryan_chen static ulong ast2600_enable_sdclk(struct ast2600_scu *scu) 604*f51926eeSryan_chen { 605*f51926eeSryan_chen u32 reset_bit; 606*f51926eeSryan_chen u32 clkstop_bit; 607*f51926eeSryan_chen 608*f51926eeSryan_chen reset_bit = BIT(ASPEED_RESET_SD - 32); 609*f51926eeSryan_chen clkstop_bit = BIT(SCU_CLKSTOP_SDIO); 610*f51926eeSryan_chen 611*f51926eeSryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 612*f51926eeSryan_chen udelay(100); 613*f51926eeSryan_chen //enable clk 614*f51926eeSryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 615*f51926eeSryan_chen mdelay(10); 616*f51926eeSryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 617*f51926eeSryan_chen 618*f51926eeSryan_chen return 0; 619*f51926eeSryan_chen } 620*f51926eeSryan_chen 621*f51926eeSryan_chen #define SCU_CLKSTOP_EXTSD 31 622*f51926eeSryan_chen #define SCU_CLK_SD_MASK (0x7 << 28) 623*f51926eeSryan_chen #define SCU_CLK_SD_DIV(x) (x << 28) 624*f51926eeSryan_chen 625*f51926eeSryan_chen static ulong ast2600_enable_extsdclk(struct ast2600_scu *scu) 626*f51926eeSryan_chen { 627*f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel4); 628*f51926eeSryan_chen u32 enableclk_bit; 629*f51926eeSryan_chen 630*f51926eeSryan_chen enableclk_bit = BIT(SCU_CLKSTOP_EXTSD); 631*f51926eeSryan_chen 632*f51926eeSryan_chen clk_sel &= ~SCU_CLK_SD_MASK; 633*f51926eeSryan_chen clk_sel |= SCU_CLK_SD_DIV(0); 634*f51926eeSryan_chen writel(clk_sel, &scu->clk_sel4); 635*f51926eeSryan_chen 636*f51926eeSryan_chen //enable clk 637*f51926eeSryan_chen setbits_le32(&scu->clk_sel4, enableclk_bit); 638*f51926eeSryan_chen 639*f51926eeSryan_chen return 0; 640*f51926eeSryan_chen } 641*f51926eeSryan_chen 642*f51926eeSryan_chen #define SCU_CLKSTOP_EMMC 27 643*f51926eeSryan_chen static ulong ast2600_enable_emmcclk(struct ast2600_scu *scu) 644*f51926eeSryan_chen { 645*f51926eeSryan_chen u32 reset_bit; 646*f51926eeSryan_chen u32 clkstop_bit; 647*f51926eeSryan_chen 648*f51926eeSryan_chen reset_bit = BIT(ASPEED_RESET_EMMC); 649*f51926eeSryan_chen clkstop_bit = BIT(SCU_CLKSTOP_EMMC); 650*f51926eeSryan_chen 651*f51926eeSryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 652*f51926eeSryan_chen udelay(100); 653*f51926eeSryan_chen //enable clk 654*f51926eeSryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 655*f51926eeSryan_chen mdelay(10); 656*f51926eeSryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 657*f51926eeSryan_chen 658*f51926eeSryan_chen return 0; 659*f51926eeSryan_chen } 660*f51926eeSryan_chen 661*f51926eeSryan_chen #define SCU_CLKSTOP_EXTEMMC 15 662*f51926eeSryan_chen #define SCU_CLK_EMMC_MASK (0x7 << 12) 663*f51926eeSryan_chen #define SCU_CLK_EMMC_DIV(x) (x << 12) 664*f51926eeSryan_chen 665*f51926eeSryan_chen static ulong ast2600_enable_extemmcclk(struct ast2600_scu *scu) 666*f51926eeSryan_chen { 667*f51926eeSryan_chen u32 clk_sel = readl(&scu->clk_sel1); 668*f51926eeSryan_chen u32 enableclk_bit; 669*f51926eeSryan_chen 670*f51926eeSryan_chen enableclk_bit = BIT(SCU_CLKSTOP_EXTSD); 671*f51926eeSryan_chen 672*f51926eeSryan_chen clk_sel &= ~SCU_CLK_SD_MASK; 673*f51926eeSryan_chen clk_sel |= SCU_CLK_SD_DIV(1); 674*f51926eeSryan_chen writel(clk_sel, &scu->clk_sel1); 675*f51926eeSryan_chen 676*f51926eeSryan_chen //enable clk 677*f51926eeSryan_chen setbits_le32(&scu->clk_sel1, enableclk_bit); 678*f51926eeSryan_chen 679*f51926eeSryan_chen return 0; 680*f51926eeSryan_chen } 681*f51926eeSryan_chen 682d6e349c7Sryan_chen static int ast2600_clk_enable(struct clk *clk) 683550e691bSryan_chen { 684f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 685550e691bSryan_chen 686550e691bSryan_chen switch (clk->id) { 68786f91560Sryan_chen case ASPEED_CLK_GATE_MAC1CLK: 68886f91560Sryan_chen ast2600_configure_mac(priv->scu, 1); 689550e691bSryan_chen break; 69086f91560Sryan_chen case ASPEED_CLK_GATE_MAC2CLK: 69186f91560Sryan_chen ast2600_configure_mac(priv->scu, 2); 692550e691bSryan_chen break; 69377843939Sryan_chen case ASPEED_CLK_GATE_MAC3CLK: 69477843939Sryan_chen ast2600_configure_mac(priv->scu, 3); 69577843939Sryan_chen break; 69677843939Sryan_chen case ASPEED_CLK_GATE_MAC4CLK: 69777843939Sryan_chen ast2600_configure_mac(priv->scu, 4); 69877843939Sryan_chen break; 699*f51926eeSryan_chen case ASPEED_CLK_GATE_SDCLK: 700*f51926eeSryan_chen ast2600_enable_sdclk(priv->scu); 701*f51926eeSryan_chen break; 702*f51926eeSryan_chen case ASPEED_CLK_GATE_SDEXTCLK: 703*f51926eeSryan_chen ast2600_enable_extsdclk(priv->scu); 704*f51926eeSryan_chen break; 705*f51926eeSryan_chen case ASPEED_CLK_GATE_EMMCCLK: 706*f51926eeSryan_chen ast2600_enable_emmcclk(priv->scu); 707*f51926eeSryan_chen break; 708*f51926eeSryan_chen case ASPEED_CLK_GATE_EMMCEXTCLK: 709*f51926eeSryan_chen ast2600_enable_extemmcclk(priv->scu); 710*f51926eeSryan_chen break; 711550e691bSryan_chen default: 712f9aa0ee1Sryan_chen pr_debug("can't enable clk \n"); 713550e691bSryan_chen return -ENOENT; 71477843939Sryan_chen break; 715550e691bSryan_chen } 716550e691bSryan_chen 717550e691bSryan_chen return 0; 718550e691bSryan_chen } 719550e691bSryan_chen 720f9aa0ee1Sryan_chen struct clk_ops ast2600_clk_ops = { 721d6e349c7Sryan_chen .get_rate = ast2600_clk_get_rate, 722d6e349c7Sryan_chen .set_rate = ast2600_clk_set_rate, 723d6e349c7Sryan_chen .enable = ast2600_clk_enable, 724550e691bSryan_chen }; 725550e691bSryan_chen 726d6e349c7Sryan_chen static int ast2600_clk_probe(struct udevice *dev) 727550e691bSryan_chen { 728f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(dev); 729550e691bSryan_chen 730f0d895afSryan_chen priv->scu = devfdt_get_addr_ptr(dev); 731f0d895afSryan_chen if (IS_ERR(priv->scu)) 732f0d895afSryan_chen return PTR_ERR(priv->scu); 733550e691bSryan_chen 734550e691bSryan_chen return 0; 735550e691bSryan_chen } 736550e691bSryan_chen 737d6e349c7Sryan_chen static int ast2600_clk_bind(struct udevice *dev) 738550e691bSryan_chen { 739550e691bSryan_chen int ret; 740550e691bSryan_chen 741550e691bSryan_chen /* The reset driver does not have a device node, so bind it here */ 742550e691bSryan_chen ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev); 743550e691bSryan_chen if (ret) 744550e691bSryan_chen debug("Warning: No reset driver: ret=%d\n", ret); 745550e691bSryan_chen 746550e691bSryan_chen return 0; 747550e691bSryan_chen } 748550e691bSryan_chen 749d6e349c7Sryan_chen static const struct udevice_id ast2600_clk_ids[] = { 750d6e349c7Sryan_chen { .compatible = "aspeed,ast2600-scu", }, 751550e691bSryan_chen { } 752550e691bSryan_chen }; 753550e691bSryan_chen 754aa36597fSDylan Hung U_BOOT_DRIVER(aspeed_scu) = { 755aa36597fSDylan Hung .name = "aspeed_scu", 756550e691bSryan_chen .id = UCLASS_CLK, 757d6e349c7Sryan_chen .of_match = ast2600_clk_ids, 758f0d895afSryan_chen .priv_auto_alloc_size = sizeof(struct ast2600_clk_priv), 759f9aa0ee1Sryan_chen .ops = &ast2600_clk_ops, 760d6e349c7Sryan_chen .bind = ast2600_clk_bind, 761d6e349c7Sryan_chen .probe = ast2600_clk_probe, 762550e691bSryan_chen }; 763