uboot/arch/mips/mach-ath79/ar934x/clk.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2016 Marek Vasut <marex@denx.de>
   4 */
   5
   6#include <common.h>
   7#include <asm/io.h>
   8#include <asm/addrspace.h>
   9#include <asm/types.h>
  10#include <mach/ar71xx_regs.h>
  11#include <mach/ath79.h>
  12#include <wait_bit.h>
  13
  14DECLARE_GLOBAL_DATA_PTR;
  15
  16/*
  17 * The math for calculating PLL:
  18 *                                       NFRAC * 2^8
  19 *                               NINT + -------------
  20 *                XTAL [MHz]              2^(18 - 1)
  21 *   PLL [MHz] = ------------ * ----------------------
  22 *                  REFDIV              2^OUTDIV
  23 *
  24 * Unfortunatelly, there is no way to reliably compute the variables.
  25 * The vendor U-Boot port contains macros for various combinations of
  26 * CPU PLL / DDR PLL / AHB bus speed and there is no obvious pattern
  27 * in those numbers.
  28 */
  29struct ar934x_pll_config {
  30        u8      range;
  31        u8      refdiv;
  32        u8      outdiv;
  33        /* Index 0 is for XTAL=25MHz , Index 1 is for XTAL=40MHz */
  34        u8      nint[2];
  35};
  36
  37struct ar934x_clock_config {
  38        u16                             cpu_freq;
  39        u16                             ddr_freq;
  40        u16                             ahb_freq;
  41
  42        struct ar934x_pll_config        cpu_pll;
  43        struct ar934x_pll_config        ddr_pll;
  44};
  45
  46static const struct ar934x_clock_config ar934x_clock_config[] = {
  47        { 300, 300, 150, { 1, 1, 1, { 24, 15 } }, { 1, 1, 1, { 24, 15 } } },
  48        { 400, 200, 200, { 1, 1, 1, { 32, 20 } }, { 1, 1, 2, { 32, 20 } } },
  49        { 400, 400, 200, { 0, 1, 1, { 32, 20 } }, { 0, 1, 1, { 32, 20 } } },
  50        { 500, 400, 200, { 1, 1, 0, { 20, 12 } }, { 0, 1, 1, { 32, 20 } } },
  51        { 533, 400, 200, { 1, 1, 0, { 21, 13 } }, { 0, 1, 1, { 32, 20 } } },
  52        { 533, 500, 250, { 1, 1, 0, { 21, 13 } }, { 0, 1, 0, { 20, 12 } } },
  53        { 560, 480, 240, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 12 } } },
  54        { 566, 400, 200, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 16, 10 } } },
  55        { 566, 450, 225, { 1, 1, 0, { 22, 14 } }, { 0, 1, 1, { 36, 22 } } },
  56        { 566, 475, 237, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 11 } } },
  57        { 566, 500, 250, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 20, 12 } } },
  58        { 566, 525, 262, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 21, 13 } } },
  59        { 566, 550, 275, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 22, 13 } } },
  60        { 600, 266, 133, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } },
  61        { 600, 266, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } },
  62        { 600, 300, 150, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 24, 15 } } },
  63        { 600, 332, 166, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } },
  64        { 600, 332, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } },
  65        { 600, 400, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 32, 20 } } },
  66        { 600, 450, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 18, 20 } } },
  67        { 600, 500, 250, { 0, 1, 0, { 24, 15 } }, { 1, 1, 0, { 20, 12 } } },
  68        { 600, 525, 262, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 21, 20 } } },
  69        { 600, 550, 275, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 22, 20 } } },
  70        { 600, 575, 287, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 23, 14 } } },
  71        { 600, 600, 300, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 24, 20 } } },
  72        { 600, 650, 325, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 26, 20 } } },
  73        { 650, 600, 300, { 0, 1, 0, { 26, 15 } }, { 0, 1, 0, { 24, 20 } } },
  74        { 700, 400, 200, { 3, 1, 0, { 28, 17 } }, { 0, 1, 1, { 32, 20 } } },
  75};
  76
  77static void ar934x_srif_pll_cfg(void __iomem *pll_reg_base, const u32 srif_val)
  78{
  79        u32 reg;
  80        do {
  81                writel(0x10810f00, pll_reg_base + 0x4);
  82                writel(srif_val, pll_reg_base + 0x0);
  83                writel(0xd0810f00, pll_reg_base + 0x4);
  84                writel(0x03000000, pll_reg_base + 0x8);
  85                writel(0xd0800f00, pll_reg_base + 0x4);
  86
  87                clrbits_be32(pll_reg_base + 0x8, BIT(30));
  88                udelay(5);
  89                setbits_be32(pll_reg_base + 0x8, BIT(30));
  90                udelay(5);
  91
  92                wait_for_bit_le32(pll_reg_base + 0xc, BIT(3), 1, 10, 0);
  93
  94                clrbits_be32(pll_reg_base + 0x8, BIT(30));
  95                udelay(5);
  96
  97                /* Check if CPU SRIF PLL locked. */
  98                reg = readl(pll_reg_base + 0x8);
  99                reg = (reg & 0x7ffff8) >> 3;
 100        } while (reg >= 0x40000);
 101}
 102
 103void ar934x_pll_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz)
 104{
 105        void __iomem *srif_regs = map_physmem(AR934X_SRIF_BASE,
 106                                              AR934X_SRIF_SIZE, MAP_NOCACHE);
 107        void __iomem *pll_regs = map_physmem(AR71XX_PLL_BASE,
 108                                             AR71XX_PLL_SIZE, MAP_NOCACHE);
 109        const struct ar934x_pll_config *pll_cfg;
 110        int i, pll_nint, pll_refdiv, xtal_40 = 0;
 111        u32 reg, cpu_pll, cpu_srif, ddr_pll, ddr_srif;
 112
 113        /* Configure SRIF PLL with initial values. */
 114        writel(0x13210f00, srif_regs + AR934X_SRIF_CPU_DPLL2_REG);
 115        writel(0x03000000, srif_regs + AR934X_SRIF_CPU_DPLL3_REG);
 116        writel(0x13210f00, srif_regs + AR934X_SRIF_DDR_DPLL2_REG);
 117        writel(0x03000000, srif_regs + AR934X_SRIF_DDR_DPLL3_REG);
 118        writel(0x03000000, srif_regs + 0x188); /* Undocumented reg :-) */
 119
 120        /* Test for 40MHz XTAL */
 121        reg = ath79_get_bootstrap();
 122        if (reg & AR934X_BOOTSTRAP_REF_CLK_40) {
 123                xtal_40 = 1;
 124                cpu_srif = 0x41c00000;
 125                ddr_srif = 0x41680000;
 126        } else {
 127                xtal_40 = 0;
 128                cpu_srif = 0x29c00000;
 129                ddr_srif = 0x29680000;
 130        }
 131
 132        /* Locate CPU/DDR PLL configuration */
 133        for (i = 0; i < ARRAY_SIZE(ar934x_clock_config); i++) {
 134                if (cpu_mhz != ar934x_clock_config[i].cpu_freq)
 135                        continue;
 136                if (ddr_mhz != ar934x_clock_config[i].ddr_freq)
 137                        continue;
 138                if (ahb_mhz != ar934x_clock_config[i].ahb_freq)
 139                        continue;
 140
 141                /* Entry found */
 142                pll_cfg = &ar934x_clock_config[i].cpu_pll;
 143                pll_nint = pll_cfg->nint[xtal_40];
 144                pll_refdiv = pll_cfg->refdiv;
 145                cpu_pll =
 146                        (pll_nint << AR934X_PLL_CPU_CONFIG_NINT_SHIFT) |
 147                        (pll_refdiv << AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) |
 148                        (pll_cfg->range << AR934X_PLL_CPU_CONFIG_RANGE_SHIFT) |
 149                        (pll_cfg->outdiv << AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT);
 150
 151                pll_cfg = &ar934x_clock_config[i].ddr_pll;
 152                pll_nint = pll_cfg->nint[xtal_40];
 153                pll_refdiv = pll_cfg->refdiv;
 154                ddr_pll =
 155                        (pll_nint << AR934X_PLL_DDR_CONFIG_NINT_SHIFT) |
 156                        (pll_refdiv << AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) |
 157                        (pll_cfg->range << AR934X_PLL_DDR_CONFIG_RANGE_SHIFT) |
 158                        (pll_cfg->outdiv << AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT);
 159                break;
 160        }
 161
 162        /* PLL configuration not found, hang. */
 163        if (i == ARRAY_SIZE(ar934x_clock_config))
 164                hang();
 165
 166        /* Set PLL Bypass */
 167        setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
 168                     AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS);
 169        setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
 170                     AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS);
 171        setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
 172                     AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS);
 173
 174        /* Configure CPU PLL */
 175        writel(cpu_pll | AR934X_PLL_CPU_CONFIG_PLLPWD,
 176               pll_regs + AR934X_PLL_CPU_CONFIG_REG);
 177        /* Configure DDR PLL */
 178        writel(ddr_pll | AR934X_PLL_DDR_CONFIG_PLLPWD,
 179               pll_regs + AR934X_PLL_DDR_CONFIG_REG);
 180        /* Configure PLL routing */
 181        writel(AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS |
 182               AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS |
 183               AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS |
 184               (0 << AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) |
 185               (0 << AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) |
 186               (1 << AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) |
 187               AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL |
 188               AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL |
 189               AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL,
 190               pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
 191
 192        /* Configure SRIF PLLs, which is completely undocumented :-) */
 193        ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_CPU_DPLL1_REG, cpu_srif);
 194        ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_DDR_DPLL1_REG, ddr_srif);
 195
 196        /* Unset PLL Bypass */
 197        clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
 198                     AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS);
 199        clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
 200                     AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS);
 201        clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
 202                     AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS);
 203
 204        /* Enable PLL dithering */
 205        writel((1 << AR934X_PLL_DDR_DIT_FRAC_STEP_SHIFT) |
 206               (0xf << AR934X_PLL_DDR_DIT_UPD_CNT_SHIFT),
 207               pll_regs + AR934X_PLL_DDR_DIT_FRAC_REG);
 208        writel(48 << AR934X_PLL_CPU_DIT_UPD_CNT_SHIFT,
 209               pll_regs + AR934X_PLL_CPU_DIT_FRAC_REG);
 210}
 211
 212static u32 ar934x_get_xtal(void)
 213{
 214        u32 val;
 215
 216        val = ath79_get_bootstrap();
 217        if (val & AR934X_BOOTSTRAP_REF_CLK_40)
 218                return 40000000;
 219        else
 220                return 25000000;
 221}
 222
 223int get_serial_clock(void)
 224{
 225        return ar934x_get_xtal();
 226}
 227
 228static u32 ar934x_cpupll_to_hz(const u32 regval)
 229{
 230        const u32 outdiv = (regval >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
 231                           AR934X_PLL_CPU_CONFIG_OUTDIV_MASK;
 232        const u32 refdiv = (regval >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
 233                           AR934X_PLL_CPU_CONFIG_REFDIV_MASK;
 234        const u32 nint = (regval >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) &
 235                           AR934X_PLL_CPU_CONFIG_NINT_MASK;
 236        const u32 nfrac = (regval >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
 237                           AR934X_PLL_CPU_CONFIG_NFRAC_MASK;
 238        const u32 xtal = ar934x_get_xtal();
 239
 240        return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv));
 241}
 242
 243static u32 ar934x_ddrpll_to_hz(const u32 regval)
 244{
 245        const u32 outdiv = (regval >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
 246                           AR934X_PLL_DDR_CONFIG_OUTDIV_MASK;
 247        const u32 refdiv = (regval >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
 248                           AR934X_PLL_DDR_CONFIG_REFDIV_MASK;
 249        const u32 nint = (regval >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) &
 250                           AR934X_PLL_DDR_CONFIG_NINT_MASK;
 251        const u32 nfrac = (regval >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
 252                           AR934X_PLL_DDR_CONFIG_NFRAC_MASK;
 253        const u32 xtal = ar934x_get_xtal();
 254
 255        return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv));
 256}
 257
 258static void ar934x_update_clock(void)
 259{
 260        void __iomem *regs;
 261        u32 ctrl, cpu, cpupll, ddr, ddrpll;
 262        u32 cpudiv, ddrdiv, busdiv;
 263        u32 cpuclk, ddrclk, busclk;
 264
 265        regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
 266                           MAP_NOCACHE);
 267
 268        cpu = readl(regs + AR934X_PLL_CPU_CONFIG_REG);
 269        ddr = readl(regs + AR934X_PLL_DDR_CONFIG_REG);
 270        ctrl = readl(regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
 271
 272        cpupll = ar934x_cpupll_to_hz(cpu);
 273        ddrpll = ar934x_ddrpll_to_hz(ddr);
 274
 275        if (ctrl & AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
 276                cpuclk = ar934x_get_xtal();
 277        else if (ctrl & AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
 278                cpuclk = cpupll;
 279        else
 280                cpuclk = ddrpll;
 281
 282        if (ctrl & AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
 283                ddrclk = ar934x_get_xtal();
 284        else if (ctrl & AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
 285                ddrclk = ddrpll;
 286        else
 287                ddrclk = cpupll;
 288
 289        if (ctrl & AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
 290                busclk = ar934x_get_xtal();
 291        else if (ctrl & AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
 292                busclk = ddrpll;
 293        else
 294                busclk = cpupll;
 295
 296        cpudiv = (ctrl >> AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
 297                 AR934X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
 298        ddrdiv = (ctrl >> AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
 299                 AR934X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
 300        busdiv = (ctrl >> AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
 301                 AR934X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
 302
 303        gd->cpu_clk = cpuclk / (cpudiv + 1);
 304        gd->mem_clk = ddrclk / (ddrdiv + 1);
 305        gd->bus_clk = busclk / (busdiv + 1);
 306}
 307
 308ulong get_bus_freq(ulong dummy)
 309{
 310        ar934x_update_clock();
 311        return gd->bus_clk;
 312}
 313
 314ulong get_ddr_freq(ulong dummy)
 315{
 316        ar934x_update_clock();
 317        return gd->mem_clk;
 318}
 319
 320int do_ar934x_showclk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 321{
 322        ar934x_update_clock();
 323        printf("CPU:       %8ld MHz\n", gd->cpu_clk / 1000000);
 324        printf("Memory:    %8ld MHz\n", gd->mem_clk / 1000000);
 325        printf("AHB:       %8ld MHz\n", gd->bus_clk / 1000000);
 326        return 0;
 327}
 328
 329U_BOOT_CMD(
 330        clocks, CONFIG_SYS_MAXARGS, 1, do_ar934x_showclk,
 331        "display clocks",
 332        ""
 333);
 334