19b03f802SWills Wang /* 29b03f802SWills Wang * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> 39b03f802SWills Wang * 49b03f802SWills Wang * SPDX-License-Identifier: GPL-2.0+ 59b03f802SWills Wang */ 69b03f802SWills Wang 79b03f802SWills Wang #include <common.h> 89b03f802SWills Wang #include <asm/io.h> 99b03f802SWills Wang #include <asm/addrspace.h> 109b03f802SWills Wang #include <asm/types.h> 119b03f802SWills Wang #include <mach/ar71xx_regs.h> 12*37523917SWills Wang #include <mach/ath79.h> 139b03f802SWills Wang 149b03f802SWills Wang DECLARE_GLOBAL_DATA_PTR; 159b03f802SWills Wang qca953x_get_xtal(void)169b03f802SWills Wangstatic u32 qca953x_get_xtal(void) 179b03f802SWills Wang { 189b03f802SWills Wang u32 val; 199b03f802SWills Wang 20*37523917SWills Wang val = ath79_get_bootstrap(); 219b03f802SWills Wang if (val & QCA953X_BOOTSTRAP_REF_CLK_40) 229b03f802SWills Wang return 40000000; 239b03f802SWills Wang else 249b03f802SWills Wang return 25000000; 259b03f802SWills Wang } 269b03f802SWills Wang get_serial_clock(void)279b03f802SWills Wangint get_serial_clock(void) 289b03f802SWills Wang { 299b03f802SWills Wang return qca953x_get_xtal(); 309b03f802SWills Wang } 319b03f802SWills Wang get_clocks(void)329b03f802SWills Wangint get_clocks(void) 339b03f802SWills Wang { 349b03f802SWills Wang void __iomem *regs; 359b03f802SWills Wang u32 val, ctrl, xtal, pll, div; 369b03f802SWills Wang 379b03f802SWills Wang regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE, 389b03f802SWills Wang MAP_NOCACHE); 399b03f802SWills Wang 409b03f802SWills Wang xtal = qca953x_get_xtal(); 419b03f802SWills Wang ctrl = readl(regs + QCA953X_PLL_CLK_CTRL_REG); 429b03f802SWills Wang val = readl(regs + QCA953X_PLL_CPU_CONFIG_REG); 439b03f802SWills Wang 449b03f802SWills Wang /* VCOOUT = XTAL * DIV_INT */ 459b03f802SWills Wang div = (val >> QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT) 469b03f802SWills Wang & QCA953X_PLL_CPU_CONFIG_REFDIV_MASK; 479b03f802SWills Wang pll = xtal / div; 489b03f802SWills Wang 499b03f802SWills Wang /* PLLOUT = VCOOUT * (1/2^OUTDIV) */ 509b03f802SWills Wang div = (val >> QCA953X_PLL_CPU_CONFIG_NINT_SHIFT) 519b03f802SWills Wang & QCA953X_PLL_CPU_CONFIG_NINT_MASK; 529b03f802SWills Wang pll *= div; 539b03f802SWills Wang div = (val >> QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT) 549b03f802SWills Wang & QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK; 559b03f802SWills Wang if (!div) 569b03f802SWills Wang div = 1; 579b03f802SWills Wang pll >>= div; 589b03f802SWills Wang 599b03f802SWills Wang /* CPU_CLK = PLLOUT / CPU_POST_DIV */ 609b03f802SWills Wang div = ((ctrl >> QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) 619b03f802SWills Wang & QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK) + 1; 629b03f802SWills Wang gd->cpu_clk = pll / div; 639b03f802SWills Wang 649b03f802SWills Wang 659b03f802SWills Wang val = readl(regs + QCA953X_PLL_DDR_CONFIG_REG); 669b03f802SWills Wang /* VCOOUT = XTAL * DIV_INT */ 679b03f802SWills Wang div = (val >> QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT) 689b03f802SWills Wang & QCA953X_PLL_DDR_CONFIG_REFDIV_MASK; 699b03f802SWills Wang pll = xtal / div; 709b03f802SWills Wang 719b03f802SWills Wang /* PLLOUT = VCOOUT * (1/2^OUTDIV) */ 729b03f802SWills Wang div = (val >> QCA953X_PLL_DDR_CONFIG_NINT_SHIFT) 739b03f802SWills Wang & QCA953X_PLL_DDR_CONFIG_NINT_MASK; 749b03f802SWills Wang pll *= div; 759b03f802SWills Wang div = (val >> QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT) 769b03f802SWills Wang & QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK; 779b03f802SWills Wang if (!div) 789b03f802SWills Wang div = 1; 799b03f802SWills Wang pll >>= div; 809b03f802SWills Wang 819b03f802SWills Wang /* DDR_CLK = PLLOUT / DDR_POST_DIV */ 829b03f802SWills Wang div = ((ctrl >> QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) 839b03f802SWills Wang & QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK) + 1; 849b03f802SWills Wang gd->mem_clk = pll / div; 859b03f802SWills Wang 869b03f802SWills Wang div = ((ctrl >> QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) 879b03f802SWills Wang & QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK) + 1; 889b03f802SWills Wang if (ctrl & QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL) { 899b03f802SWills Wang /* AHB_CLK = DDR_CLK / AHB_POST_DIV */ 909b03f802SWills Wang gd->bus_clk = gd->mem_clk / (div + 1); 919b03f802SWills Wang } else { 929b03f802SWills Wang /* AHB_CLK = CPU_CLK / AHB_POST_DIV */ 939b03f802SWills Wang gd->bus_clk = gd->cpu_clk / (div + 1); 949b03f802SWills Wang } 959b03f802SWills Wang 969b03f802SWills Wang return 0; 979b03f802SWills Wang } 989b03f802SWills Wang get_bus_freq(ulong dummy)999b03f802SWills Wangulong get_bus_freq(ulong dummy) 1009b03f802SWills Wang { 1019b03f802SWills Wang if (!gd->bus_clk) 1029b03f802SWills Wang get_clocks(); 1039b03f802SWills Wang return gd->bus_clk; 1049b03f802SWills Wang } 1059b03f802SWills Wang get_ddr_freq(ulong dummy)1069b03f802SWills Wangulong get_ddr_freq(ulong dummy) 1079b03f802SWills Wang { 1089b03f802SWills Wang if (!gd->mem_clk) 1099b03f802SWills Wang get_clocks(); 1109b03f802SWills Wang return gd->mem_clk; 1119b03f802SWills Wang } 112