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 99*f9aa0ee1Sryan_chen extern u32 ast2600_get_dpll_rate(struct ast2600_scu *scu) 100*f9aa0ee1Sryan_chen { 101*f9aa0ee1Sryan_chen u32 clk_in = AST2600_CLK_IN; 102*f9aa0ee1Sryan_chen u32 dpll_reg = readl(&scu->d_pll_param); 103*f9aa0ee1Sryan_chen unsigned int mult, div = 1; 104*f9aa0ee1Sryan_chen 105*f9aa0ee1Sryan_chen if (dpll_reg & BIT(24)) { 106*f9aa0ee1Sryan_chen /* Pass through mode */ 107*f9aa0ee1Sryan_chen mult = div = 1; 108*f9aa0ee1Sryan_chen } else { 109*f9aa0ee1Sryan_chen /* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1)*/ 110*f9aa0ee1Sryan_chen u32 m = dpll_reg & 0x1fff; 111*f9aa0ee1Sryan_chen u32 n = (dpll_reg >> 13) & 0x3f; 112*f9aa0ee1Sryan_chen u32 p = (dpll_reg >> 19) & 0x7; 113*f9aa0ee1Sryan_chen mult = ((m + 1) / (n + 1)); 114*f9aa0ee1Sryan_chen div = (p + 1); 115*f9aa0ee1Sryan_chen } 116*f9aa0ee1Sryan_chen return (clk_in * mult)/div; 117*f9aa0ee1Sryan_chen } 118*f9aa0ee1Sryan_chen 11927881d20Sryan_chen static u32 ast2600_a0_axi_ahb_div_table[] = { 12027881d20Sryan_chen 2, 2, 3, 5, 12127881d20Sryan_chen }; 12227881d20Sryan_chen 12327881d20Sryan_chen static u32 ast2600_a1_axi_ahb_div_table[] = { 12427881d20Sryan_chen 4, 6, 2, 4, 12527881d20Sryan_chen }; 12627881d20Sryan_chen 12727881d20Sryan_chen static u32 ast2600_get_hclk(struct ast2600_scu *scu) 12827881d20Sryan_chen { 12927881d20Sryan_chen u32 hw_rev = readl(&scu->chip_id0); 13027881d20Sryan_chen u32 hwstrap1 = readl(&scu->hwstrap1); 13127881d20Sryan_chen u32 axi_div = 1; 13227881d20Sryan_chen u32 ahb_div = 0; 13327881d20Sryan_chen u32 rate = 0; 13427881d20Sryan_chen 13527881d20Sryan_chen if((hwstrap1 >> 16) & 0x1) 13627881d20Sryan_chen axi_div = 1; 13727881d20Sryan_chen else 13827881d20Sryan_chen axi_div = 2; 13927881d20Sryan_chen 14027881d20Sryan_chen if (hw_rev & BIT(16)) 14127881d20Sryan_chen ahb_div = ast2600_a1_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 14227881d20Sryan_chen else 14327881d20Sryan_chen ahb_div = ast2600_a0_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3]; 14427881d20Sryan_chen 14527881d20Sryan_chen rate = ast2600_get_hpll_rate(scu); 14627881d20Sryan_chen rate = rate / axi_div / ahb_div; 14727881d20Sryan_chen 14827881d20Sryan_chen return rate; 14927881d20Sryan_chen } 15027881d20Sryan_chen 1514f22e838Sryan_chen extern u32 ast2600_get_apll_rate(struct ast2600_scu *scu) 152550e691bSryan_chen { 15339283ea7Sryan_chen u32 clk_in = AST2600_CLK_IN; 15439283ea7Sryan_chen u32 apll_reg = readl(&scu->a_pll_param); 15539283ea7Sryan_chen unsigned int mult, div = 1; 156d6e349c7Sryan_chen 15739283ea7Sryan_chen if (apll_reg & BIT(20)) { 158d6e349c7Sryan_chen /* Pass through mode */ 159d6e349c7Sryan_chen mult = div = 1; 160d6e349c7Sryan_chen } else { 161d6e349c7Sryan_chen /* F = 25Mhz * (2-OD) * [(M + 2) / (n + 1)] */ 16239283ea7Sryan_chen u32 m = (apll_reg >> 5) & 0x3f; 16339283ea7Sryan_chen u32 od = (apll_reg >> 4) & 0x1; 16439283ea7Sryan_chen u32 n = apll_reg & 0xf; 165d6e349c7Sryan_chen 16639283ea7Sryan_chen mult = (2 - od) * ((m + 2) / (n + 1)); 167d6e349c7Sryan_chen } 168d6e349c7Sryan_chen return (clk_in * mult)/div; 169d6e349c7Sryan_chen } 170d6e349c7Sryan_chen 1714f22e838Sryan_chen extern u32 ast2600_get_epll_rate(struct ast2600_scu *scu) 17239283ea7Sryan_chen { 17339283ea7Sryan_chen u32 clk_in = AST2600_CLK_IN; 17439283ea7Sryan_chen u32 epll_reg = readl(&scu->e_pll_param); 17539283ea7Sryan_chen unsigned int mult, div = 1; 17639283ea7Sryan_chen 17739283ea7Sryan_chen if (epll_reg & BIT(24)) { 17839283ea7Sryan_chen /* Pass through mode */ 17939283ea7Sryan_chen mult = div = 1; 18039283ea7Sryan_chen } else { 18139283ea7Sryan_chen /* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1)*/ 18239283ea7Sryan_chen u32 m = epll_reg & 0x1fff; 18339283ea7Sryan_chen u32 n = (epll_reg >> 13) & 0x3f; 18439283ea7Sryan_chen u32 p = (epll_reg >> 19) & 0x7; 18539283ea7Sryan_chen 18639283ea7Sryan_chen mult = ((m + 1) / (n + 1)); 18739283ea7Sryan_chen div = (p + 1); 18839283ea7Sryan_chen } 18939283ea7Sryan_chen return (clk_in * mult)/div; 19039283ea7Sryan_chen } 19139283ea7Sryan_chen 192d6e349c7Sryan_chen 19327881d20Sryan_chen static u32 ast2600_get_uxclk_rate(struct ast2600_scu *scu) 194d6e349c7Sryan_chen { 19527881d20Sryan_chen u32 clk_in = 0; 19627881d20Sryan_chen u32 uxclk_sel = readl(&scu->clk_sel4); 197550e691bSryan_chen 19827881d20Sryan_chen uxclk_sel &= 0x3; 19927881d20Sryan_chen switch(uxclk_sel) { 20027881d20Sryan_chen case 0: 20127881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 4; 20227881d20Sryan_chen break; 20327881d20Sryan_chen case 1: 20427881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 2; 20527881d20Sryan_chen break; 20627881d20Sryan_chen case 2: 20727881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu); 20827881d20Sryan_chen break; 20927881d20Sryan_chen case 3: 21027881d20Sryan_chen clk_in = ast2600_get_hclk(scu); 21127881d20Sryan_chen break; 21227881d20Sryan_chen } 213d6e349c7Sryan_chen 21427881d20Sryan_chen return clk_in; 21527881d20Sryan_chen } 21627881d20Sryan_chen 21727881d20Sryan_chen static u32 ast2600_get_huxclk_rate(struct ast2600_scu *scu) 21827881d20Sryan_chen { 21927881d20Sryan_chen u32 clk_in = 0; 22027881d20Sryan_chen u32 huclk_sel = readl(&scu->clk_sel4); 22127881d20Sryan_chen 22227881d20Sryan_chen huclk_sel = ((huclk_sel >> 3) & 0x3); 22327881d20Sryan_chen switch(huclk_sel) { 22427881d20Sryan_chen case 0: 22527881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 4; 22627881d20Sryan_chen break; 22727881d20Sryan_chen case 1: 22827881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu) / 2; 22927881d20Sryan_chen break; 23027881d20Sryan_chen case 2: 23127881d20Sryan_chen clk_in = ast2600_get_apll_rate(scu); 23227881d20Sryan_chen break; 23327881d20Sryan_chen case 3: 23427881d20Sryan_chen clk_in = ast2600_get_hclk(scu); 23527881d20Sryan_chen break; 23627881d20Sryan_chen } 23727881d20Sryan_chen 23827881d20Sryan_chen return clk_in; 23927881d20Sryan_chen } 24027881d20Sryan_chen 24127881d20Sryan_chen static u32 ast2600_get_uart_from_uxclk_rate(struct ast2600_scu *scu) 24227881d20Sryan_chen { 24327881d20Sryan_chen u32 clk_in = ast2600_get_uxclk_rate(scu); 24427881d20Sryan_chen u32 div_reg = readl(&scu->uart_24m_ref_uxclk); 24527881d20Sryan_chen unsigned int mult, div; 24627881d20Sryan_chen 24727881d20Sryan_chen u32 n = (div_reg >> 8) & 0x3ff; 24827881d20Sryan_chen u32 r = div_reg & 0xff; 24927881d20Sryan_chen 25027881d20Sryan_chen mult = r; 25127881d20Sryan_chen div = (n * 4); 25227881d20Sryan_chen return (clk_in * mult)/div; 25327881d20Sryan_chen } 25427881d20Sryan_chen 25527881d20Sryan_chen static u32 ast2600_get_uart_from_huxclk_rate(struct ast2600_scu *scu) 25627881d20Sryan_chen { 25727881d20Sryan_chen u32 clk_in = ast2600_get_huxclk_rate(scu); 25827881d20Sryan_chen u32 div_reg = readl(&scu->uart_24m_ref_huxclk); 25927881d20Sryan_chen 26027881d20Sryan_chen unsigned int mult, div; 26127881d20Sryan_chen 26227881d20Sryan_chen u32 n = (div_reg >> 8) & 0x3ff; 26327881d20Sryan_chen u32 r = div_reg & 0xff; 26427881d20Sryan_chen 26527881d20Sryan_chen mult = r; 26627881d20Sryan_chen div = (n * 4); 26727881d20Sryan_chen return (clk_in * mult)/div; 26827881d20Sryan_chen } 26927881d20Sryan_chen 27027881d20Sryan_chen static ulong ast2600_get_uart_clk_rate(struct ast2600_scu *scu, int uart_idx) 27127881d20Sryan_chen { 27227881d20Sryan_chen u32 uart_sel = readl(&scu->clk_sel4); 27327881d20Sryan_chen u32 uart_sel5 = readl(&scu->clk_sel5); 27427881d20Sryan_chen ulong uart_clk = 0; 27527881d20Sryan_chen 27627881d20Sryan_chen switch(uart_idx) { 27727881d20Sryan_chen case 1: 27827881d20Sryan_chen case 2: 27927881d20Sryan_chen case 3: 28027881d20Sryan_chen case 4: 28127881d20Sryan_chen case 6: 28227881d20Sryan_chen if(uart_sel & BIT(uart_idx - 1)) 28327881d20Sryan_chen uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ; 284550e691bSryan_chen else 28527881d20Sryan_chen uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ; 28627881d20Sryan_chen break; 28727881d20Sryan_chen case 5: //24mhz is come form usb phy 48Mhz 28827881d20Sryan_chen { 28927881d20Sryan_chen u8 uart5_clk_sel = 0; 29027881d20Sryan_chen //high bit 29127881d20Sryan_chen if (readl(&scu->misc_ctrl1) & BIT(12)) 29227881d20Sryan_chen uart5_clk_sel = 0x2; 29327881d20Sryan_chen else 29427881d20Sryan_chen uart5_clk_sel = 0x0; 295550e691bSryan_chen 29627881d20Sryan_chen if (readl(&scu->clk_sel2) & BIT(14)) 29727881d20Sryan_chen uart5_clk_sel |= 0x1; 298550e691bSryan_chen 29927881d20Sryan_chen switch(uart5_clk_sel) { 30027881d20Sryan_chen case 0: 30127881d20Sryan_chen uart_clk = 24000000; 30227881d20Sryan_chen break; 30327881d20Sryan_chen case 1: 30427881d20Sryan_chen uart_clk = 0; 30527881d20Sryan_chen break; 30627881d20Sryan_chen case 2: 30727881d20Sryan_chen uart_clk = 24000000/13; 30827881d20Sryan_chen break; 30927881d20Sryan_chen case 3: 31027881d20Sryan_chen uart_clk = 192000000/13; 31127881d20Sryan_chen break; 31227881d20Sryan_chen } 31327881d20Sryan_chen } 31427881d20Sryan_chen break; 31527881d20Sryan_chen case 7: 31627881d20Sryan_chen case 8: 31727881d20Sryan_chen case 9: 31827881d20Sryan_chen case 10: 31927881d20Sryan_chen case 11: 32027881d20Sryan_chen case 12: 32127881d20Sryan_chen case 13: 32227881d20Sryan_chen if(uart_sel5 & BIT(uart_idx - 1)) 32327881d20Sryan_chen uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ; 32427881d20Sryan_chen else 32527881d20Sryan_chen uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ; 32627881d20Sryan_chen break; 32727881d20Sryan_chen } 32827881d20Sryan_chen 32927881d20Sryan_chen return uart_clk; 330550e691bSryan_chen } 331550e691bSryan_chen 332550e691bSryan_chen struct aspeed_clock_config { 333550e691bSryan_chen ulong input_rate; 334550e691bSryan_chen ulong rate; 33539283ea7Sryan_chen struct ast2600_div_config cfg; 336550e691bSryan_chen }; 337550e691bSryan_chen 338550e691bSryan_chen static const struct aspeed_clock_config aspeed_clock_config_defaults[] = { 3391cd71a14SDylan Hung { 25000000, 400000000, { .num = 95, .denum = 2, .post_div = 1 } }, 340550e691bSryan_chen }; 341550e691bSryan_chen 342550e691bSryan_chen static bool aspeed_get_clock_config_default(ulong input_rate, 343550e691bSryan_chen ulong requested_rate, 34439283ea7Sryan_chen struct ast2600_div_config *cfg) 345550e691bSryan_chen { 346550e691bSryan_chen int i; 347550e691bSryan_chen 348550e691bSryan_chen for (i = 0; i < ARRAY_SIZE(aspeed_clock_config_defaults); i++) { 349550e691bSryan_chen const struct aspeed_clock_config *default_cfg = 350550e691bSryan_chen &aspeed_clock_config_defaults[i]; 351550e691bSryan_chen if (default_cfg->input_rate == input_rate && 352550e691bSryan_chen default_cfg->rate == requested_rate) { 353550e691bSryan_chen *cfg = default_cfg->cfg; 354550e691bSryan_chen return true; 355550e691bSryan_chen } 356550e691bSryan_chen } 357550e691bSryan_chen 358550e691bSryan_chen return false; 359550e691bSryan_chen } 360550e691bSryan_chen 361550e691bSryan_chen /* 362550e691bSryan_chen * @input_rate - the rate of input clock in Hz 363550e691bSryan_chen * @requested_rate - desired output rate in Hz 364550e691bSryan_chen * @div - this is an IN/OUT parameter, at input all fields of the config 365550e691bSryan_chen * need to be set to their maximum allowed values. 366550e691bSryan_chen * The result (the best config we could find), would also be returned 367550e691bSryan_chen * in this structure. 368550e691bSryan_chen * 369550e691bSryan_chen * @return The clock rate, when the resulting div_config is used. 370550e691bSryan_chen */ 371550e691bSryan_chen static ulong aspeed_calc_clock_config(ulong input_rate, ulong requested_rate, 37239283ea7Sryan_chen struct ast2600_div_config *cfg) 373550e691bSryan_chen { 374550e691bSryan_chen /* 375550e691bSryan_chen * The assumption is that kHz precision is good enough and 376550e691bSryan_chen * also enough to avoid overflow when multiplying. 377550e691bSryan_chen */ 378550e691bSryan_chen const ulong input_rate_khz = input_rate / 1000; 379550e691bSryan_chen const ulong rate_khz = requested_rate / 1000; 38039283ea7Sryan_chen const struct ast2600_div_config max_vals = *cfg; 38139283ea7Sryan_chen struct ast2600_div_config it = { 0, 0, 0 }; 382550e691bSryan_chen ulong delta = rate_khz; 383550e691bSryan_chen ulong new_rate_khz = 0; 384550e691bSryan_chen 385550e691bSryan_chen /* 386550e691bSryan_chen * Look for a well known frequency first. 387550e691bSryan_chen */ 388550e691bSryan_chen if (aspeed_get_clock_config_default(input_rate, requested_rate, cfg)) 389550e691bSryan_chen return requested_rate; 390550e691bSryan_chen 391550e691bSryan_chen for (; it.denum <= max_vals.denum; ++it.denum) { 392550e691bSryan_chen for (it.post_div = 0; it.post_div <= max_vals.post_div; 393550e691bSryan_chen ++it.post_div) { 394550e691bSryan_chen it.num = (rate_khz * (it.post_div + 1) / input_rate_khz) 395550e691bSryan_chen * (it.denum + 1); 396550e691bSryan_chen if (it.num > max_vals.num) 397550e691bSryan_chen continue; 398550e691bSryan_chen 399550e691bSryan_chen new_rate_khz = (input_rate_khz 400550e691bSryan_chen * ((it.num + 1) / (it.denum + 1))) 401550e691bSryan_chen / (it.post_div + 1); 402550e691bSryan_chen 403550e691bSryan_chen /* Keep the rate below requested one. */ 404550e691bSryan_chen if (new_rate_khz > rate_khz) 405550e691bSryan_chen continue; 406550e691bSryan_chen 407550e691bSryan_chen if (new_rate_khz - rate_khz < delta) { 408550e691bSryan_chen delta = new_rate_khz - rate_khz; 409550e691bSryan_chen *cfg = it; 410550e691bSryan_chen if (delta == 0) 411550e691bSryan_chen return new_rate_khz * 1000; 412550e691bSryan_chen } 413550e691bSryan_chen } 414550e691bSryan_chen } 415550e691bSryan_chen 416550e691bSryan_chen return new_rate_khz * 1000; 417550e691bSryan_chen } 418550e691bSryan_chen 41939283ea7Sryan_chen static u32 ast2600_configure_ddr(struct ast2600_clk_priv *priv, ulong rate) 420550e691bSryan_chen { 421d6e349c7Sryan_chen u32 clkin = AST2600_CLK_IN; 422550e691bSryan_chen u32 mpll_reg; 42339283ea7Sryan_chen struct ast2600_div_config div_cfg = { 424550e691bSryan_chen .num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT), 425550e691bSryan_chen .denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT), 426550e691bSryan_chen .post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT), 427550e691bSryan_chen }; 428550e691bSryan_chen 429550e691bSryan_chen aspeed_calc_clock_config(clkin, rate, &div_cfg); 430550e691bSryan_chen 431f0d895afSryan_chen mpll_reg = readl(&priv->scu->m_pll_param); 432550e691bSryan_chen mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK 433550e691bSryan_chen | SCU_MPLL_DENUM_MASK); 434550e691bSryan_chen mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT) 435550e691bSryan_chen | (div_cfg.num << SCU_MPLL_NUM_SHIFT) 436550e691bSryan_chen | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT); 437550e691bSryan_chen 438f0d895afSryan_chen writel(mpll_reg, &priv->scu->m_pll_param); 439550e691bSryan_chen 44039283ea7Sryan_chen return ast2600_get_mpll_rate(priv->scu); 441550e691bSryan_chen } 442550e691bSryan_chen 443f0d895afSryan_chen static u32 ast2600_hpll_pclk_div_table[] = { 444f0d895afSryan_chen 4, 8, 12, 16, 20, 24, 28, 32, 445f0d895afSryan_chen }; 446d6e349c7Sryan_chen static ulong ast2600_clk_get_rate(struct clk *clk) 447d6e349c7Sryan_chen { 448f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 44927881d20Sryan_chen ulong rate = 0; 450d6e349c7Sryan_chen 451d6e349c7Sryan_chen switch (clk->id) { 452d1e64dd1Sryan_chen //HPLL 453d1e64dd1Sryan_chen case ASPEED_CLK_HPLL: 45439283ea7Sryan_chen rate = ast2600_get_hpll_rate(priv->scu); 455d6e349c7Sryan_chen break; 456d1e64dd1Sryan_chen //HCLK 457d1e64dd1Sryan_chen case ASPEED_CLK_AHB: 45827881d20Sryan_chen rate = ast2600_get_hclk(priv->scu); 459d1e64dd1Sryan_chen break; 460f0d895afSryan_chen case ASPEED_CLK_MPLL: 46139283ea7Sryan_chen rate = ast2600_get_mpll_rate(priv->scu); 462d6e349c7Sryan_chen break; 46339283ea7Sryan_chen //pclk 46439283ea7Sryan_chen case ASPEED_CLK_APB: 465d6e349c7Sryan_chen { 466f0d895afSryan_chen u32 clk_sel1 = readl(&priv->scu->clk_sel1); 467f0d895afSryan_chen u32 apb_div = ast2600_hpll_pclk_div_table[((clk_sel1 >> 23) & 0x7)]; 46839283ea7Sryan_chen rate = ast2600_get_hpll_rate(priv->scu); 469d6e349c7Sryan_chen rate = rate / apb_div; 470d6e349c7Sryan_chen } 471d6e349c7Sryan_chen break; 47227881d20Sryan_chen case ASPEED_CLK_GATE_UART1CLK: 47327881d20Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 1); 474d6e349c7Sryan_chen break; 47527881d20Sryan_chen case ASPEED_CLK_GATE_UART2CLK: 47627881d20Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 2); 477d6e349c7Sryan_chen break; 47827881d20Sryan_chen case ASPEED_CLK_GATE_UART3CLK: 47927881d20Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 3); 480d6e349c7Sryan_chen break; 48127881d20Sryan_chen case ASPEED_CLK_GATE_UART4CLK: 48227881d20Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 4); 483d6e349c7Sryan_chen break; 484d1e64dd1Sryan_chen case ASPEED_CLK_GATE_UART5CLK: 48527881d20Sryan_chen rate = ast2600_get_uart_clk_rate(priv->scu, 5); 486d6e349c7Sryan_chen break; 487d6e349c7Sryan_chen default: 488d6e349c7Sryan_chen return -ENOENT; 489d6e349c7Sryan_chen } 490d6e349c7Sryan_chen 491d6e349c7Sryan_chen return rate; 492d6e349c7Sryan_chen } 493d6e349c7Sryan_chen 494d6e349c7Sryan_chen static ulong ast2600_clk_set_rate(struct clk *clk, ulong rate) 495550e691bSryan_chen { 496f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 497550e691bSryan_chen 498550e691bSryan_chen ulong new_rate; 499550e691bSryan_chen switch (clk->id) { 500f0d895afSryan_chen case ASPEED_CLK_MPLL: 50139283ea7Sryan_chen new_rate = ast2600_configure_ddr(priv, rate); 502550e691bSryan_chen break; 503550e691bSryan_chen default: 504550e691bSryan_chen return -ENOENT; 505550e691bSryan_chen } 506550e691bSryan_chen 507550e691bSryan_chen return new_rate; 508550e691bSryan_chen } 509*f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC1 (20) 510*f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC2 (21) 511*f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC3 (20) 512*f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC4 (21) 513*f9aa0ee1Sryan_chen 514*f9aa0ee1Sryan_chen static u32 ast2600_configure_mac(struct ast2600_scu *scu, int index) 515*f9aa0ee1Sryan_chen { 516*f9aa0ee1Sryan_chen u32 reset_bit; 517*f9aa0ee1Sryan_chen u32 clkstop_bit; 518*f9aa0ee1Sryan_chen 519*f9aa0ee1Sryan_chen 520*f9aa0ee1Sryan_chen switch (index) { 521*f9aa0ee1Sryan_chen case 1: 522*f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC1); 523*f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC1); 524*f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl1); 525*f9aa0ee1Sryan_chen udelay(100); 526*f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 527*f9aa0ee1Sryan_chen mdelay(10); 528*f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 529*f9aa0ee1Sryan_chen 530*f9aa0ee1Sryan_chen break; 531*f9aa0ee1Sryan_chen case 2: 532*f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC2); 533*f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC2); 534*f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl1); 535*f9aa0ee1Sryan_chen udelay(100); 536*f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl1); 537*f9aa0ee1Sryan_chen mdelay(10); 538*f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl1); 539*f9aa0ee1Sryan_chen break; 540*f9aa0ee1Sryan_chen case 3: 541*f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC3 - 32); 542*f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC3); 543*f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 544*f9aa0ee1Sryan_chen udelay(100); 545*f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 546*f9aa0ee1Sryan_chen mdelay(10); 547*f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 548*f9aa0ee1Sryan_chen break; 549*f9aa0ee1Sryan_chen case 4: 550*f9aa0ee1Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC4 - 32); 551*f9aa0ee1Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC4); 552*f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_ctrl2); 553*f9aa0ee1Sryan_chen udelay(100); 554*f9aa0ee1Sryan_chen writel(clkstop_bit, &scu->clk_stop_clr_ctrl2); 555*f9aa0ee1Sryan_chen mdelay(10); 556*f9aa0ee1Sryan_chen writel(reset_bit, &scu->sysreset_clr_ctrl2); 557*f9aa0ee1Sryan_chen break; 558*f9aa0ee1Sryan_chen default: 559*f9aa0ee1Sryan_chen return -EINVAL; 560*f9aa0ee1Sryan_chen } 561*f9aa0ee1Sryan_chen 562*f9aa0ee1Sryan_chen return 0; 563*f9aa0ee1Sryan_chen } 564550e691bSryan_chen 565d6e349c7Sryan_chen static int ast2600_clk_enable(struct clk *clk) 566550e691bSryan_chen { 567f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(clk->dev); 568550e691bSryan_chen 569550e691bSryan_chen switch (clk->id) { 57086f91560Sryan_chen case ASPEED_CLK_GATE_MAC1CLK: 57186f91560Sryan_chen ast2600_configure_mac(priv->scu, 1); 572550e691bSryan_chen break; 57386f91560Sryan_chen case ASPEED_CLK_GATE_MAC2CLK: 57486f91560Sryan_chen ast2600_configure_mac(priv->scu, 2); 575550e691bSryan_chen break; 57677843939Sryan_chen case ASPEED_CLK_GATE_MAC3CLK: 57777843939Sryan_chen ast2600_configure_mac(priv->scu, 3); 57877843939Sryan_chen break; 57977843939Sryan_chen case ASPEED_CLK_GATE_MAC4CLK: 58077843939Sryan_chen ast2600_configure_mac(priv->scu, 4); 58177843939Sryan_chen break; 582550e691bSryan_chen default: 583*f9aa0ee1Sryan_chen pr_debug("can't enable clk \n"); 584550e691bSryan_chen return -ENOENT; 58577843939Sryan_chen break; 586550e691bSryan_chen } 587550e691bSryan_chen 588550e691bSryan_chen return 0; 589550e691bSryan_chen } 590550e691bSryan_chen 591*f9aa0ee1Sryan_chen struct clk_ops ast2600_clk_ops = { 592d6e349c7Sryan_chen .get_rate = ast2600_clk_get_rate, 593d6e349c7Sryan_chen .set_rate = ast2600_clk_set_rate, 594d6e349c7Sryan_chen .enable = ast2600_clk_enable, 595550e691bSryan_chen }; 596550e691bSryan_chen 597d6e349c7Sryan_chen static int ast2600_clk_probe(struct udevice *dev) 598550e691bSryan_chen { 599f0d895afSryan_chen struct ast2600_clk_priv *priv = dev_get_priv(dev); 600550e691bSryan_chen 601f0d895afSryan_chen priv->scu = devfdt_get_addr_ptr(dev); 602f0d895afSryan_chen if (IS_ERR(priv->scu)) 603f0d895afSryan_chen return PTR_ERR(priv->scu); 604550e691bSryan_chen 605550e691bSryan_chen return 0; 606550e691bSryan_chen } 607550e691bSryan_chen 608d6e349c7Sryan_chen static int ast2600_clk_bind(struct udevice *dev) 609550e691bSryan_chen { 610550e691bSryan_chen int ret; 611550e691bSryan_chen 612550e691bSryan_chen /* The reset driver does not have a device node, so bind it here */ 613550e691bSryan_chen ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev); 614550e691bSryan_chen if (ret) 615550e691bSryan_chen debug("Warning: No reset driver: ret=%d\n", ret); 616550e691bSryan_chen 617550e691bSryan_chen return 0; 618550e691bSryan_chen } 619550e691bSryan_chen 620d6e349c7Sryan_chen static const struct udevice_id ast2600_clk_ids[] = { 621d6e349c7Sryan_chen { .compatible = "aspeed,ast2600-scu", }, 622550e691bSryan_chen { } 623550e691bSryan_chen }; 624550e691bSryan_chen 625aa36597fSDylan Hung U_BOOT_DRIVER(aspeed_scu) = { 626aa36597fSDylan Hung .name = "aspeed_scu", 627550e691bSryan_chen .id = UCLASS_CLK, 628d6e349c7Sryan_chen .of_match = ast2600_clk_ids, 629f0d895afSryan_chen .priv_auto_alloc_size = sizeof(struct ast2600_clk_priv), 630*f9aa0ee1Sryan_chen .ops = &ast2600_clk_ops, 631d6e349c7Sryan_chen .bind = ast2600_clk_bind, 632d6e349c7Sryan_chen .probe = ast2600_clk_probe, 633550e691bSryan_chen }; 634