linux/arch/mips/ath79/clock.c
<<
>>
Prefs
   1/*
   2 *  Atheros AR71XX/AR724X/AR913X common routines
   3 *
   4 *  Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
   5 *  Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
   6 *
   7 *  Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP
   8 *
   9 *  This program is free software; you can redistribute it and/or modify it
  10 *  under the terms of the GNU General Public License version 2 as published
  11 *  by the Free Software Foundation.
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/init.h>
  17#include <linux/err.h>
  18#include <linux/clk.h>
  19
  20#include <asm/mach-ath79/ath79.h>
  21#include <asm/mach-ath79/ar71xx_regs.h>
  22#include "common.h"
  23
  24#define AR71XX_BASE_FREQ        40000000
  25#define AR724X_BASE_FREQ        5000000
  26#define AR913X_BASE_FREQ        5000000
  27
  28struct clk {
  29        unsigned long rate;
  30};
  31
  32static struct clk ath79_ref_clk;
  33static struct clk ath79_cpu_clk;
  34static struct clk ath79_ddr_clk;
  35static struct clk ath79_ahb_clk;
  36static struct clk ath79_wdt_clk;
  37static struct clk ath79_uart_clk;
  38
  39static void __init ar71xx_clocks_init(void)
  40{
  41        u32 pll;
  42        u32 freq;
  43        u32 div;
  44
  45        ath79_ref_clk.rate = AR71XX_BASE_FREQ;
  46
  47        pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
  48
  49        div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1;
  50        freq = div * ath79_ref_clk.rate;
  51
  52        div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
  53        ath79_cpu_clk.rate = freq / div;
  54
  55        div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
  56        ath79_ddr_clk.rate = freq / div;
  57
  58        div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
  59        ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
  60
  61        ath79_wdt_clk.rate = ath79_ahb_clk.rate;
  62        ath79_uart_clk.rate = ath79_ahb_clk.rate;
  63}
  64
  65static void __init ar724x_clocks_init(void)
  66{
  67        u32 pll;
  68        u32 freq;
  69        u32 div;
  70
  71        ath79_ref_clk.rate = AR724X_BASE_FREQ;
  72        pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
  73
  74        div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK);
  75        freq = div * ath79_ref_clk.rate;
  76
  77        div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
  78        freq *= div;
  79
  80        ath79_cpu_clk.rate = freq;
  81
  82        div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
  83        ath79_ddr_clk.rate = freq / div;
  84
  85        div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
  86        ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
  87
  88        ath79_wdt_clk.rate = ath79_ahb_clk.rate;
  89        ath79_uart_clk.rate = ath79_ahb_clk.rate;
  90}
  91
  92static void __init ar913x_clocks_init(void)
  93{
  94        u32 pll;
  95        u32 freq;
  96        u32 div;
  97
  98        ath79_ref_clk.rate = AR913X_BASE_FREQ;
  99        pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG);
 100
 101        div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK);
 102        freq = div * ath79_ref_clk.rate;
 103
 104        ath79_cpu_clk.rate = freq;
 105
 106        div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1;
 107        ath79_ddr_clk.rate = freq / div;
 108
 109        div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2;
 110        ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
 111
 112        ath79_wdt_clk.rate = ath79_ahb_clk.rate;
 113        ath79_uart_clk.rate = ath79_ahb_clk.rate;
 114}
 115
 116static void __init ar933x_clocks_init(void)
 117{
 118        u32 clock_ctrl;
 119        u32 cpu_config;
 120        u32 freq;
 121        u32 t;
 122
 123        t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
 124        if (t & AR933X_BOOTSTRAP_REF_CLK_40)
 125                ath79_ref_clk.rate = (40 * 1000 * 1000);
 126        else
 127                ath79_ref_clk.rate = (25 * 1000 * 1000);
 128
 129        clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG);
 130        if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) {
 131                ath79_cpu_clk.rate = ath79_ref_clk.rate;
 132                ath79_ahb_clk.rate = ath79_ref_clk.rate;
 133                ath79_ddr_clk.rate = ath79_ref_clk.rate;
 134        } else {
 135                cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG);
 136
 137                t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
 138                    AR933X_PLL_CPU_CONFIG_REFDIV_MASK;
 139                freq = ath79_ref_clk.rate / t;
 140
 141                t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) &
 142                    AR933X_PLL_CPU_CONFIG_NINT_MASK;
 143                freq *= t;
 144
 145                t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
 146                    AR933X_PLL_CPU_CONFIG_OUTDIV_MASK;
 147                if (t == 0)
 148                        t = 1;
 149
 150                freq >>= t;
 151
 152                t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) &
 153                     AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1;
 154                ath79_cpu_clk.rate = freq / t;
 155
 156                t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) &
 157                      AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1;
 158                ath79_ddr_clk.rate = freq / t;
 159
 160                t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) &
 161                     AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1;
 162                ath79_ahb_clk.rate = freq / t;
 163        }
 164
 165        ath79_wdt_clk.rate = ath79_ref_clk.rate;
 166        ath79_uart_clk.rate = ath79_ref_clk.rate;
 167}
 168
 169static void __init ar934x_clocks_init(void)
 170{
 171        u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv;
 172        u32 cpu_pll, ddr_pll;
 173        u32 bootstrap;
 174
 175        bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP);
 176        if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40)
 177                ath79_ref_clk.rate = 40 * 1000 * 1000;
 178        else
 179                ath79_ref_clk.rate = 25 * 1000 * 1000;
 180
 181        pll = ath79_pll_rr(AR934X_PLL_CPU_CONFIG_REG);
 182        out_div = (pll >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
 183                  AR934X_PLL_CPU_CONFIG_OUTDIV_MASK;
 184        ref_div = (pll >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
 185                  AR934X_PLL_CPU_CONFIG_REFDIV_MASK;
 186        nint = (pll >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) &
 187               AR934X_PLL_CPU_CONFIG_NINT_MASK;
 188        frac = (pll >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
 189               AR934X_PLL_CPU_CONFIG_NFRAC_MASK;
 190
 191        cpu_pll = nint * ath79_ref_clk.rate / ref_div;
 192        cpu_pll += frac * ath79_ref_clk.rate / (ref_div * (2 << 6));
 193        cpu_pll /= (1 << out_div);
 194
 195        pll = ath79_pll_rr(AR934X_PLL_DDR_CONFIG_REG);
 196        out_div = (pll >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
 197                  AR934X_PLL_DDR_CONFIG_OUTDIV_MASK;
 198        ref_div = (pll >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
 199                  AR934X_PLL_DDR_CONFIG_REFDIV_MASK;
 200        nint = (pll >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) &
 201               AR934X_PLL_DDR_CONFIG_NINT_MASK;
 202        frac = (pll >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
 203               AR934X_PLL_DDR_CONFIG_NFRAC_MASK;
 204
 205        ddr_pll = nint * ath79_ref_clk.rate / ref_div;
 206        ddr_pll += frac * ath79_ref_clk.rate / (ref_div * (2 << 10));
 207        ddr_pll /= (1 << out_div);
 208
 209        clk_ctrl = ath79_pll_rr(AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
 210
 211        postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT) &
 212                  AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK;
 213
 214        if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS)
 215                ath79_cpu_clk.rate = ath79_ref_clk.rate;
 216        else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL)
 217                ath79_cpu_clk.rate = cpu_pll / (postdiv + 1);
 218        else
 219                ath79_cpu_clk.rate = ddr_pll / (postdiv + 1);
 220
 221        postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) &
 222                  AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK;
 223
 224        if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS)
 225                ath79_ddr_clk.rate = ath79_ref_clk.rate;
 226        else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL)
 227                ath79_ddr_clk.rate = ddr_pll / (postdiv + 1);
 228        else
 229                ath79_ddr_clk.rate = cpu_pll / (postdiv + 1);
 230
 231        postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) &
 232                  AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK;
 233
 234        if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS)
 235                ath79_ahb_clk.rate = ath79_ref_clk.rate;
 236        else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL)
 237                ath79_ahb_clk.rate = ddr_pll / (postdiv + 1);
 238        else
 239                ath79_ahb_clk.rate = cpu_pll / (postdiv + 1);
 240
 241        ath79_wdt_clk.rate = ath79_ref_clk.rate;
 242        ath79_uart_clk.rate = ath79_ref_clk.rate;
 243}
 244
 245void __init ath79_clocks_init(void)
 246{
 247        if (soc_is_ar71xx())
 248                ar71xx_clocks_init();
 249        else if (soc_is_ar724x())
 250                ar724x_clocks_init();
 251        else if (soc_is_ar913x())
 252                ar913x_clocks_init();
 253        else if (soc_is_ar933x())
 254                ar933x_clocks_init();
 255        else if (soc_is_ar934x())
 256                ar934x_clocks_init();
 257        else
 258                BUG();
 259
 260        pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, "
 261                "Ref:%lu.%03luMHz",
 262                ath79_cpu_clk.rate / 1000000,
 263                (ath79_cpu_clk.rate / 1000) % 1000,
 264                ath79_ddr_clk.rate / 1000000,
 265                (ath79_ddr_clk.rate / 1000) % 1000,
 266                ath79_ahb_clk.rate / 1000000,
 267                (ath79_ahb_clk.rate / 1000) % 1000,
 268                ath79_ref_clk.rate / 1000000,
 269                (ath79_ref_clk.rate / 1000) % 1000);
 270}
 271
 272/*
 273 * Linux clock API
 274 */
 275struct clk *clk_get(struct device *dev, const char *id)
 276{
 277        if (!strcmp(id, "ref"))
 278                return &ath79_ref_clk;
 279
 280        if (!strcmp(id, "cpu"))
 281                return &ath79_cpu_clk;
 282
 283        if (!strcmp(id, "ddr"))
 284                return &ath79_ddr_clk;
 285
 286        if (!strcmp(id, "ahb"))
 287                return &ath79_ahb_clk;
 288
 289        if (!strcmp(id, "wdt"))
 290                return &ath79_wdt_clk;
 291
 292        if (!strcmp(id, "uart"))
 293                return &ath79_uart_clk;
 294
 295        return ERR_PTR(-ENOENT);
 296}
 297EXPORT_SYMBOL(clk_get);
 298
 299int clk_enable(struct clk *clk)
 300{
 301        return 0;
 302}
 303EXPORT_SYMBOL(clk_enable);
 304
 305void clk_disable(struct clk *clk)
 306{
 307}
 308EXPORT_SYMBOL(clk_disable);
 309
 310unsigned long clk_get_rate(struct clk *clk)
 311{
 312        return clk->rate;
 313}
 314EXPORT_SYMBOL(clk_get_rate);
 315
 316void clk_put(struct clk *clk)
 317{
 318}
 319EXPORT_SYMBOL(clk_put);
 320