1d4a67d9dSGabor Juhos /* 2d4a67d9dSGabor Juhos * Atheros AR71XX/AR724X/AR913X common routines 3d4a67d9dSGabor Juhos * 48889612bSGabor Juhos * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> 5d4a67d9dSGabor Juhos * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> 6d4a67d9dSGabor Juhos * 78889612bSGabor Juhos * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP 88889612bSGabor Juhos * 9d4a67d9dSGabor Juhos * This program is free software; you can redistribute it and/or modify it 10d4a67d9dSGabor Juhos * under the terms of the GNU General Public License version 2 as published 11d4a67d9dSGabor Juhos * by the Free Software Foundation. 12d4a67d9dSGabor Juhos */ 13d4a67d9dSGabor Juhos 14d4a67d9dSGabor Juhos #include <linux/kernel.h> 15d4a67d9dSGabor Juhos #include <linux/module.h> 16d4a67d9dSGabor Juhos #include <linux/init.h> 17d4a67d9dSGabor Juhos #include <linux/err.h> 18d4a67d9dSGabor Juhos #include <linux/clk.h> 192c4f1ac5SGabor Juhos #include <linux/clkdev.h> 20d4a67d9dSGabor Juhos 2197541ccfSGabor Juhos #include <asm/div64.h> 2297541ccfSGabor Juhos 23d4a67d9dSGabor Juhos #include <asm/mach-ath79/ath79.h> 24d4a67d9dSGabor Juhos #include <asm/mach-ath79/ar71xx_regs.h> 25d4a67d9dSGabor Juhos #include "common.h" 26d4a67d9dSGabor Juhos 27d4a67d9dSGabor Juhos #define AR71XX_BASE_FREQ 40000000 28d4a67d9dSGabor Juhos #define AR724X_BASE_FREQ 5000000 29d4a67d9dSGabor Juhos #define AR913X_BASE_FREQ 5000000 30d4a67d9dSGabor Juhos 31d4a67d9dSGabor Juhos struct clk { 32d4a67d9dSGabor Juhos unsigned long rate; 33d4a67d9dSGabor Juhos }; 34d4a67d9dSGabor Juhos 352c4f1ac5SGabor Juhos static void __init ath79_add_sys_clkdev(const char *id, unsigned long rate) 362c4f1ac5SGabor Juhos { 372c4f1ac5SGabor Juhos struct clk *clk; 382c4f1ac5SGabor Juhos int err; 392c4f1ac5SGabor Juhos 402c4f1ac5SGabor Juhos clk = kzalloc(sizeof(*clk), GFP_KERNEL); 412c4f1ac5SGabor Juhos if (!clk) 422c4f1ac5SGabor Juhos panic("failed to allocate %s clock structure", id); 432c4f1ac5SGabor Juhos 442c4f1ac5SGabor Juhos clk->rate = rate; 452c4f1ac5SGabor Juhos 462c4f1ac5SGabor Juhos err = clk_register_clkdev(clk, id, NULL); 472c4f1ac5SGabor Juhos if (err) 482c4f1ac5SGabor Juhos panic("unable to register %s clock device", id); 492c4f1ac5SGabor Juhos } 50d4a67d9dSGabor Juhos 51d4a67d9dSGabor Juhos static void __init ar71xx_clocks_init(void) 52d4a67d9dSGabor Juhos { 536612a688SGabor Juhos unsigned long ref_rate; 546612a688SGabor Juhos unsigned long cpu_rate; 556612a688SGabor Juhos unsigned long ddr_rate; 566612a688SGabor Juhos unsigned long ahb_rate; 57d4a67d9dSGabor Juhos u32 pll; 58d4a67d9dSGabor Juhos u32 freq; 59d4a67d9dSGabor Juhos u32 div; 60d4a67d9dSGabor Juhos 616612a688SGabor Juhos ref_rate = AR71XX_BASE_FREQ; 62d4a67d9dSGabor Juhos 63d4a67d9dSGabor Juhos pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG); 64d4a67d9dSGabor Juhos 65*626a0695SAlban Bedel div = ((pll >> AR71XX_PLL_FB_SHIFT) & AR71XX_PLL_FB_MASK) + 1; 666612a688SGabor Juhos freq = div * ref_rate; 67d4a67d9dSGabor Juhos 68d4a67d9dSGabor Juhos div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; 696612a688SGabor Juhos cpu_rate = freq / div; 70d4a67d9dSGabor Juhos 71d4a67d9dSGabor Juhos div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1; 726612a688SGabor Juhos ddr_rate = freq / div; 73d4a67d9dSGabor Juhos 74d4a67d9dSGabor Juhos div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2; 756612a688SGabor Juhos ahb_rate = cpu_rate / div; 766612a688SGabor Juhos 772c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ref", ref_rate); 782c4f1ac5SGabor Juhos ath79_add_sys_clkdev("cpu", cpu_rate); 792c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ddr", ddr_rate); 802c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ahb", ahb_rate); 81d4a67d9dSGabor Juhos 822c4f1ac5SGabor Juhos clk_add_alias("wdt", NULL, "ahb", NULL); 832c4f1ac5SGabor Juhos clk_add_alias("uart", NULL, "ahb", NULL); 84d4a67d9dSGabor Juhos } 85d4a67d9dSGabor Juhos 86d4a67d9dSGabor Juhos static void __init ar724x_clocks_init(void) 87d4a67d9dSGabor Juhos { 886612a688SGabor Juhos unsigned long ref_rate; 896612a688SGabor Juhos unsigned long cpu_rate; 906612a688SGabor Juhos unsigned long ddr_rate; 916612a688SGabor Juhos unsigned long ahb_rate; 92d4a67d9dSGabor Juhos u32 pll; 93d4a67d9dSGabor Juhos u32 freq; 94d4a67d9dSGabor Juhos u32 div; 95d4a67d9dSGabor Juhos 966612a688SGabor Juhos ref_rate = AR724X_BASE_FREQ; 97d4a67d9dSGabor Juhos pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG); 98d4a67d9dSGabor Juhos 99*626a0695SAlban Bedel div = ((pll >> AR724X_PLL_FB_SHIFT) & AR724X_PLL_FB_MASK); 1006612a688SGabor Juhos freq = div * ref_rate; 101d4a67d9dSGabor Juhos 102d4a67d9dSGabor Juhos div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); 103d4a67d9dSGabor Juhos freq *= div; 104d4a67d9dSGabor Juhos 1056612a688SGabor Juhos cpu_rate = freq; 106d4a67d9dSGabor Juhos 107d4a67d9dSGabor Juhos div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; 1086612a688SGabor Juhos ddr_rate = freq / div; 109d4a67d9dSGabor Juhos 110d4a67d9dSGabor Juhos div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; 1116612a688SGabor Juhos ahb_rate = cpu_rate / div; 1126612a688SGabor Juhos 1132c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ref", ref_rate); 1142c4f1ac5SGabor Juhos ath79_add_sys_clkdev("cpu", cpu_rate); 1152c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ddr", ddr_rate); 1162c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ahb", ahb_rate); 117d4a67d9dSGabor Juhos 1182c4f1ac5SGabor Juhos clk_add_alias("wdt", NULL, "ahb", NULL); 1192c4f1ac5SGabor Juhos clk_add_alias("uart", NULL, "ahb", NULL); 120d4a67d9dSGabor Juhos } 121d4a67d9dSGabor Juhos 122d4a67d9dSGabor Juhos static void __init ar913x_clocks_init(void) 123d4a67d9dSGabor Juhos { 1246612a688SGabor Juhos unsigned long ref_rate; 1256612a688SGabor Juhos unsigned long cpu_rate; 1266612a688SGabor Juhos unsigned long ddr_rate; 1276612a688SGabor Juhos unsigned long ahb_rate; 128d4a67d9dSGabor Juhos u32 pll; 129d4a67d9dSGabor Juhos u32 freq; 130d4a67d9dSGabor Juhos u32 div; 131d4a67d9dSGabor Juhos 1326612a688SGabor Juhos ref_rate = AR913X_BASE_FREQ; 133d4a67d9dSGabor Juhos pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG); 134d4a67d9dSGabor Juhos 135*626a0695SAlban Bedel div = ((pll >> AR913X_PLL_FB_SHIFT) & AR913X_PLL_FB_MASK); 1366612a688SGabor Juhos freq = div * ref_rate; 137d4a67d9dSGabor Juhos 1386612a688SGabor Juhos cpu_rate = freq; 139d4a67d9dSGabor Juhos 140d4a67d9dSGabor Juhos div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1; 1416612a688SGabor Juhos ddr_rate = freq / div; 142d4a67d9dSGabor Juhos 143d4a67d9dSGabor Juhos div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2; 1446612a688SGabor Juhos ahb_rate = cpu_rate / div; 1456612a688SGabor Juhos 1462c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ref", ref_rate); 1472c4f1ac5SGabor Juhos ath79_add_sys_clkdev("cpu", cpu_rate); 1482c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ddr", ddr_rate); 1492c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ahb", ahb_rate); 150d4a67d9dSGabor Juhos 1512c4f1ac5SGabor Juhos clk_add_alias("wdt", NULL, "ahb", NULL); 1522c4f1ac5SGabor Juhos clk_add_alias("uart", NULL, "ahb", NULL); 153d4a67d9dSGabor Juhos } 154d4a67d9dSGabor Juhos 15504225e1dSGabor Juhos static void __init ar933x_clocks_init(void) 15604225e1dSGabor Juhos { 1576612a688SGabor Juhos unsigned long ref_rate; 1586612a688SGabor Juhos unsigned long cpu_rate; 1596612a688SGabor Juhos unsigned long ddr_rate; 1606612a688SGabor Juhos unsigned long ahb_rate; 16104225e1dSGabor Juhos u32 clock_ctrl; 16204225e1dSGabor Juhos u32 cpu_config; 16304225e1dSGabor Juhos u32 freq; 16404225e1dSGabor Juhos u32 t; 16504225e1dSGabor Juhos 16604225e1dSGabor Juhos t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); 16704225e1dSGabor Juhos if (t & AR933X_BOOTSTRAP_REF_CLK_40) 1686612a688SGabor Juhos ref_rate = (40 * 1000 * 1000); 16904225e1dSGabor Juhos else 1706612a688SGabor Juhos ref_rate = (25 * 1000 * 1000); 17104225e1dSGabor Juhos 17204225e1dSGabor Juhos clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG); 17304225e1dSGabor Juhos if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { 1746612a688SGabor Juhos cpu_rate = ref_rate; 1756612a688SGabor Juhos ahb_rate = ref_rate; 1766612a688SGabor Juhos ddr_rate = ref_rate; 17704225e1dSGabor Juhos } else { 17804225e1dSGabor Juhos cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG); 17904225e1dSGabor Juhos 18004225e1dSGabor Juhos t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & 18104225e1dSGabor Juhos AR933X_PLL_CPU_CONFIG_REFDIV_MASK; 1826612a688SGabor Juhos freq = ref_rate / t; 18304225e1dSGabor Juhos 18404225e1dSGabor Juhos t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & 18504225e1dSGabor Juhos AR933X_PLL_CPU_CONFIG_NINT_MASK; 18604225e1dSGabor Juhos freq *= t; 18704225e1dSGabor Juhos 18804225e1dSGabor Juhos t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & 18904225e1dSGabor Juhos AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; 19004225e1dSGabor Juhos if (t == 0) 19104225e1dSGabor Juhos t = 1; 19204225e1dSGabor Juhos 19304225e1dSGabor Juhos freq >>= t; 19404225e1dSGabor Juhos 19504225e1dSGabor Juhos t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & 19604225e1dSGabor Juhos AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1; 1976612a688SGabor Juhos cpu_rate = freq / t; 19804225e1dSGabor Juhos 19904225e1dSGabor Juhos t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & 20004225e1dSGabor Juhos AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1; 2016612a688SGabor Juhos ddr_rate = freq / t; 20204225e1dSGabor Juhos 20304225e1dSGabor Juhos t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & 20404225e1dSGabor Juhos AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1; 2056612a688SGabor Juhos ahb_rate = freq / t; 20604225e1dSGabor Juhos } 20704225e1dSGabor Juhos 2082c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ref", ref_rate); 2092c4f1ac5SGabor Juhos ath79_add_sys_clkdev("cpu", cpu_rate); 2102c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ddr", ddr_rate); 2112c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ahb", ahb_rate); 2126612a688SGabor Juhos 2132c4f1ac5SGabor Juhos clk_add_alias("wdt", NULL, "ahb", NULL); 2142c4f1ac5SGabor Juhos clk_add_alias("uart", NULL, "ref", NULL); 21504225e1dSGabor Juhos } 21604225e1dSGabor Juhos 21797541ccfSGabor Juhos static u32 __init ar934x_get_pll_freq(u32 ref, u32 ref_div, u32 nint, u32 nfrac, 21897541ccfSGabor Juhos u32 frac, u32 out_div) 21997541ccfSGabor Juhos { 22097541ccfSGabor Juhos u64 t; 22197541ccfSGabor Juhos u32 ret; 22297541ccfSGabor Juhos 223837f036cSGabor Juhos t = ref; 22497541ccfSGabor Juhos t *= nint; 22597541ccfSGabor Juhos do_div(t, ref_div); 22697541ccfSGabor Juhos ret = t; 22797541ccfSGabor Juhos 228837f036cSGabor Juhos t = ref; 22997541ccfSGabor Juhos t *= nfrac; 23097541ccfSGabor Juhos do_div(t, ref_div * frac); 23197541ccfSGabor Juhos ret += t; 23297541ccfSGabor Juhos 23397541ccfSGabor Juhos ret /= (1 << out_div); 23497541ccfSGabor Juhos return ret; 23597541ccfSGabor Juhos } 23697541ccfSGabor Juhos 2378889612bSGabor Juhos static void __init ar934x_clocks_init(void) 2388889612bSGabor Juhos { 2396612a688SGabor Juhos unsigned long ref_rate; 2406612a688SGabor Juhos unsigned long cpu_rate; 2416612a688SGabor Juhos unsigned long ddr_rate; 2426612a688SGabor Juhos unsigned long ahb_rate; 24397541ccfSGabor Juhos u32 pll, out_div, ref_div, nint, nfrac, frac, clk_ctrl, postdiv; 2448889612bSGabor Juhos u32 cpu_pll, ddr_pll; 2458889612bSGabor Juhos u32 bootstrap; 24697541ccfSGabor Juhos void __iomem *dpll_base; 24797541ccfSGabor Juhos 24897541ccfSGabor Juhos dpll_base = ioremap(AR934X_SRIF_BASE, AR934X_SRIF_SIZE); 2498889612bSGabor Juhos 2508889612bSGabor Juhos bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); 2518889612bSGabor Juhos if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40) 2526612a688SGabor Juhos ref_rate = 40 * 1000 * 1000; 2538889612bSGabor Juhos else 2546612a688SGabor Juhos ref_rate = 25 * 1000 * 1000; 2558889612bSGabor Juhos 25697541ccfSGabor Juhos pll = __raw_readl(dpll_base + AR934X_SRIF_CPU_DPLL2_REG); 25797541ccfSGabor Juhos if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) { 25897541ccfSGabor Juhos out_div = (pll >> AR934X_SRIF_DPLL2_OUTDIV_SHIFT) & 25997541ccfSGabor Juhos AR934X_SRIF_DPLL2_OUTDIV_MASK; 26097541ccfSGabor Juhos pll = __raw_readl(dpll_base + AR934X_SRIF_CPU_DPLL1_REG); 26197541ccfSGabor Juhos nint = (pll >> AR934X_SRIF_DPLL1_NINT_SHIFT) & 26297541ccfSGabor Juhos AR934X_SRIF_DPLL1_NINT_MASK; 26397541ccfSGabor Juhos nfrac = pll & AR934X_SRIF_DPLL1_NFRAC_MASK; 26497541ccfSGabor Juhos ref_div = (pll >> AR934X_SRIF_DPLL1_REFDIV_SHIFT) & 26597541ccfSGabor Juhos AR934X_SRIF_DPLL1_REFDIV_MASK; 26697541ccfSGabor Juhos frac = 1 << 18; 26797541ccfSGabor Juhos } else { 2688889612bSGabor Juhos pll = ath79_pll_rr(AR934X_PLL_CPU_CONFIG_REG); 2698889612bSGabor Juhos out_div = (pll >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & 2708889612bSGabor Juhos AR934X_PLL_CPU_CONFIG_OUTDIV_MASK; 2718889612bSGabor Juhos ref_div = (pll >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) & 2728889612bSGabor Juhos AR934X_PLL_CPU_CONFIG_REFDIV_MASK; 2738889612bSGabor Juhos nint = (pll >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) & 2748889612bSGabor Juhos AR934X_PLL_CPU_CONFIG_NINT_MASK; 27597541ccfSGabor Juhos nfrac = (pll >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) & 2768889612bSGabor Juhos AR934X_PLL_CPU_CONFIG_NFRAC_MASK; 27797541ccfSGabor Juhos frac = 1 << 6; 27897541ccfSGabor Juhos } 2798889612bSGabor Juhos 2806612a688SGabor Juhos cpu_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint, 28197541ccfSGabor Juhos nfrac, frac, out_div); 2828889612bSGabor Juhos 28397541ccfSGabor Juhos pll = __raw_readl(dpll_base + AR934X_SRIF_DDR_DPLL2_REG); 28497541ccfSGabor Juhos if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) { 28597541ccfSGabor Juhos out_div = (pll >> AR934X_SRIF_DPLL2_OUTDIV_SHIFT) & 28697541ccfSGabor Juhos AR934X_SRIF_DPLL2_OUTDIV_MASK; 28797541ccfSGabor Juhos pll = __raw_readl(dpll_base + AR934X_SRIF_DDR_DPLL1_REG); 28897541ccfSGabor Juhos nint = (pll >> AR934X_SRIF_DPLL1_NINT_SHIFT) & 28997541ccfSGabor Juhos AR934X_SRIF_DPLL1_NINT_MASK; 29097541ccfSGabor Juhos nfrac = pll & AR934X_SRIF_DPLL1_NFRAC_MASK; 29197541ccfSGabor Juhos ref_div = (pll >> AR934X_SRIF_DPLL1_REFDIV_SHIFT) & 29297541ccfSGabor Juhos AR934X_SRIF_DPLL1_REFDIV_MASK; 29397541ccfSGabor Juhos frac = 1 << 18; 29497541ccfSGabor Juhos } else { 2958889612bSGabor Juhos pll = ath79_pll_rr(AR934X_PLL_DDR_CONFIG_REG); 2968889612bSGabor Juhos out_div = (pll >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) & 2978889612bSGabor Juhos AR934X_PLL_DDR_CONFIG_OUTDIV_MASK; 2988889612bSGabor Juhos ref_div = (pll >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) & 2998889612bSGabor Juhos AR934X_PLL_DDR_CONFIG_REFDIV_MASK; 3008889612bSGabor Juhos nint = (pll >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) & 3018889612bSGabor Juhos AR934X_PLL_DDR_CONFIG_NINT_MASK; 30297541ccfSGabor Juhos nfrac = (pll >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) & 3038889612bSGabor Juhos AR934X_PLL_DDR_CONFIG_NFRAC_MASK; 30497541ccfSGabor Juhos frac = 1 << 10; 30597541ccfSGabor Juhos } 3068889612bSGabor Juhos 3076612a688SGabor Juhos ddr_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint, 30897541ccfSGabor Juhos nfrac, frac, out_div); 3098889612bSGabor Juhos 3108889612bSGabor Juhos clk_ctrl = ath79_pll_rr(AR934X_PLL_CPU_DDR_CLK_CTRL_REG); 3118889612bSGabor Juhos 3128889612bSGabor Juhos postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT) & 3138889612bSGabor Juhos AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK; 3148889612bSGabor Juhos 3158889612bSGabor Juhos if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS) 3166612a688SGabor Juhos cpu_rate = ref_rate; 3178889612bSGabor Juhos else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL) 3186612a688SGabor Juhos cpu_rate = cpu_pll / (postdiv + 1); 3198889612bSGabor Juhos else 3206612a688SGabor Juhos cpu_rate = ddr_pll / (postdiv + 1); 3218889612bSGabor Juhos 3228889612bSGabor Juhos postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) & 3238889612bSGabor Juhos AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK; 3248889612bSGabor Juhos 3258889612bSGabor Juhos if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS) 3266612a688SGabor Juhos ddr_rate = ref_rate; 3278889612bSGabor Juhos else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL) 3286612a688SGabor Juhos ddr_rate = ddr_pll / (postdiv + 1); 3298889612bSGabor Juhos else 3306612a688SGabor Juhos ddr_rate = cpu_pll / (postdiv + 1); 3318889612bSGabor Juhos 3328889612bSGabor Juhos postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) & 3338889612bSGabor Juhos AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK; 3348889612bSGabor Juhos 3358889612bSGabor Juhos if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS) 3366612a688SGabor Juhos ahb_rate = ref_rate; 3378889612bSGabor Juhos else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL) 3386612a688SGabor Juhos ahb_rate = ddr_pll / (postdiv + 1); 3398889612bSGabor Juhos else 3406612a688SGabor Juhos ahb_rate = cpu_pll / (postdiv + 1); 3416612a688SGabor Juhos 3422c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ref", ref_rate); 3432c4f1ac5SGabor Juhos ath79_add_sys_clkdev("cpu", cpu_rate); 3442c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ddr", ddr_rate); 3452c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ahb", ahb_rate); 3468889612bSGabor Juhos 3472c4f1ac5SGabor Juhos clk_add_alias("wdt", NULL, "ref", NULL); 3482c4f1ac5SGabor Juhos clk_add_alias("uart", NULL, "ref", NULL); 34997541ccfSGabor Juhos 35097541ccfSGabor Juhos iounmap(dpll_base); 3518889612bSGabor Juhos } 3528889612bSGabor Juhos 35341583c05SGabor Juhos static void __init qca955x_clocks_init(void) 35441583c05SGabor Juhos { 3556612a688SGabor Juhos unsigned long ref_rate; 3566612a688SGabor Juhos unsigned long cpu_rate; 3576612a688SGabor Juhos unsigned long ddr_rate; 3586612a688SGabor Juhos unsigned long ahb_rate; 35941583c05SGabor Juhos u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv; 36041583c05SGabor Juhos u32 cpu_pll, ddr_pll; 36141583c05SGabor Juhos u32 bootstrap; 36241583c05SGabor Juhos 36341583c05SGabor Juhos bootstrap = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP); 36441583c05SGabor Juhos if (bootstrap & QCA955X_BOOTSTRAP_REF_CLK_40) 3656612a688SGabor Juhos ref_rate = 40 * 1000 * 1000; 36641583c05SGabor Juhos else 3676612a688SGabor Juhos ref_rate = 25 * 1000 * 1000; 36841583c05SGabor Juhos 36941583c05SGabor Juhos pll = ath79_pll_rr(QCA955X_PLL_CPU_CONFIG_REG); 37041583c05SGabor Juhos out_div = (pll >> QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & 37141583c05SGabor Juhos QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK; 37241583c05SGabor Juhos ref_div = (pll >> QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT) & 37341583c05SGabor Juhos QCA955X_PLL_CPU_CONFIG_REFDIV_MASK; 37441583c05SGabor Juhos nint = (pll >> QCA955X_PLL_CPU_CONFIG_NINT_SHIFT) & 37541583c05SGabor Juhos QCA955X_PLL_CPU_CONFIG_NINT_MASK; 37641583c05SGabor Juhos frac = (pll >> QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT) & 37741583c05SGabor Juhos QCA955X_PLL_CPU_CONFIG_NFRAC_MASK; 37841583c05SGabor Juhos 3796612a688SGabor Juhos cpu_pll = nint * ref_rate / ref_div; 3806612a688SGabor Juhos cpu_pll += frac * ref_rate / (ref_div * (1 << 6)); 38141583c05SGabor Juhos cpu_pll /= (1 << out_div); 38241583c05SGabor Juhos 38341583c05SGabor Juhos pll = ath79_pll_rr(QCA955X_PLL_DDR_CONFIG_REG); 38441583c05SGabor Juhos out_div = (pll >> QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT) & 38541583c05SGabor Juhos QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK; 38641583c05SGabor Juhos ref_div = (pll >> QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT) & 38741583c05SGabor Juhos QCA955X_PLL_DDR_CONFIG_REFDIV_MASK; 38841583c05SGabor Juhos nint = (pll >> QCA955X_PLL_DDR_CONFIG_NINT_SHIFT) & 38941583c05SGabor Juhos QCA955X_PLL_DDR_CONFIG_NINT_MASK; 39041583c05SGabor Juhos frac = (pll >> QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT) & 39141583c05SGabor Juhos QCA955X_PLL_DDR_CONFIG_NFRAC_MASK; 39241583c05SGabor Juhos 3936612a688SGabor Juhos ddr_pll = nint * ref_rate / ref_div; 3946612a688SGabor Juhos ddr_pll += frac * ref_rate / (ref_div * (1 << 10)); 39541583c05SGabor Juhos ddr_pll /= (1 << out_div); 39641583c05SGabor Juhos 39741583c05SGabor Juhos clk_ctrl = ath79_pll_rr(QCA955X_PLL_CLK_CTRL_REG); 39841583c05SGabor Juhos 39941583c05SGabor Juhos postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) & 40041583c05SGabor Juhos QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK; 40141583c05SGabor Juhos 40241583c05SGabor Juhos if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS) 4036612a688SGabor Juhos cpu_rate = ref_rate; 40441583c05SGabor Juhos else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL) 4056612a688SGabor Juhos cpu_rate = ddr_pll / (postdiv + 1); 40641583c05SGabor Juhos else 4076612a688SGabor Juhos cpu_rate = cpu_pll / (postdiv + 1); 40841583c05SGabor Juhos 40941583c05SGabor Juhos postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) & 41041583c05SGabor Juhos QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK; 41141583c05SGabor Juhos 41241583c05SGabor Juhos if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS) 4136612a688SGabor Juhos ddr_rate = ref_rate; 41441583c05SGabor Juhos else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL) 4156612a688SGabor Juhos ddr_rate = cpu_pll / (postdiv + 1); 41641583c05SGabor Juhos else 4176612a688SGabor Juhos ddr_rate = ddr_pll / (postdiv + 1); 41841583c05SGabor Juhos 41941583c05SGabor Juhos postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) & 42041583c05SGabor Juhos QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK; 42141583c05SGabor Juhos 42241583c05SGabor Juhos if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS) 4236612a688SGabor Juhos ahb_rate = ref_rate; 42441583c05SGabor Juhos else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL) 4256612a688SGabor Juhos ahb_rate = ddr_pll / (postdiv + 1); 42641583c05SGabor Juhos else 4276612a688SGabor Juhos ahb_rate = cpu_pll / (postdiv + 1); 4286612a688SGabor Juhos 4292c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ref", ref_rate); 4302c4f1ac5SGabor Juhos ath79_add_sys_clkdev("cpu", cpu_rate); 4312c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ddr", ddr_rate); 4322c4f1ac5SGabor Juhos ath79_add_sys_clkdev("ahb", ahb_rate); 43341583c05SGabor Juhos 4342c4f1ac5SGabor Juhos clk_add_alias("wdt", NULL, "ref", NULL); 4352c4f1ac5SGabor Juhos clk_add_alias("uart", NULL, "ref", NULL); 43641583c05SGabor Juhos } 43741583c05SGabor Juhos 438d4a67d9dSGabor Juhos void __init ath79_clocks_init(void) 439d4a67d9dSGabor Juhos { 440d4a67d9dSGabor Juhos if (soc_is_ar71xx()) 441d4a67d9dSGabor Juhos ar71xx_clocks_init(); 442d4a67d9dSGabor Juhos else if (soc_is_ar724x()) 443d4a67d9dSGabor Juhos ar724x_clocks_init(); 444d4a67d9dSGabor Juhos else if (soc_is_ar913x()) 445d4a67d9dSGabor Juhos ar913x_clocks_init(); 44604225e1dSGabor Juhos else if (soc_is_ar933x()) 44704225e1dSGabor Juhos ar933x_clocks_init(); 4488889612bSGabor Juhos else if (soc_is_ar934x()) 4498889612bSGabor Juhos ar934x_clocks_init(); 45041583c05SGabor Juhos else if (soc_is_qca955x()) 45141583c05SGabor Juhos qca955x_clocks_init(); 452d4a67d9dSGabor Juhos else 453d4a67d9dSGabor Juhos BUG(); 454d4a67d9dSGabor Juhos } 455d4a67d9dSGabor Juhos 45623107802SGabor Juhos unsigned long __init 45723107802SGabor Juhos ath79_get_sys_clk_rate(const char *id) 45823107802SGabor Juhos { 45923107802SGabor Juhos struct clk *clk; 46023107802SGabor Juhos unsigned long rate; 46123107802SGabor Juhos 46223107802SGabor Juhos clk = clk_get(NULL, id); 46323107802SGabor Juhos if (IS_ERR(clk)) 46423107802SGabor Juhos panic("unable to get %s clock, err=%d", id, (int) PTR_ERR(clk)); 46523107802SGabor Juhos 46623107802SGabor Juhos rate = clk_get_rate(clk); 46723107802SGabor Juhos clk_put(clk); 46823107802SGabor Juhos 46923107802SGabor Juhos return rate; 47023107802SGabor Juhos } 47123107802SGabor Juhos 472d4a67d9dSGabor Juhos /* 473d4a67d9dSGabor Juhos * Linux clock API 474d4a67d9dSGabor Juhos */ 475d4a67d9dSGabor Juhos int clk_enable(struct clk *clk) 476d4a67d9dSGabor Juhos { 477d4a67d9dSGabor Juhos return 0; 478d4a67d9dSGabor Juhos } 479d4a67d9dSGabor Juhos EXPORT_SYMBOL(clk_enable); 480d4a67d9dSGabor Juhos 481d4a67d9dSGabor Juhos void clk_disable(struct clk *clk) 482d4a67d9dSGabor Juhos { 483d4a67d9dSGabor Juhos } 484d4a67d9dSGabor Juhos EXPORT_SYMBOL(clk_disable); 485d4a67d9dSGabor Juhos 486d4a67d9dSGabor Juhos unsigned long clk_get_rate(struct clk *clk) 487d4a67d9dSGabor Juhos { 488d4a67d9dSGabor Juhos return clk->rate; 489d4a67d9dSGabor Juhos } 490d4a67d9dSGabor Juhos EXPORT_SYMBOL(clk_get_rate); 491