uboot/arch/mips/mach-ath79/qca953x/clk.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
   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
  13DECLARE_GLOBAL_DATA_PTR;
  14
  15static u32 qca953x_get_xtal(void)
  16{
  17        u32 val;
  18
  19        val = ath79_get_bootstrap();
  20        if (val & QCA953X_BOOTSTRAP_REF_CLK_40)
  21                return 40000000;
  22        else
  23                return 25000000;
  24}
  25
  26int get_serial_clock(void)
  27{
  28        return qca953x_get_xtal();
  29}
  30
  31int get_clocks(void)
  32{
  33        void __iomem *regs;
  34        u32 val, ctrl, xtal, pll, div;
  35
  36        regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
  37                           MAP_NOCACHE);
  38
  39        xtal = qca953x_get_xtal();
  40        ctrl = readl(regs + QCA953X_PLL_CLK_CTRL_REG);
  41        val = readl(regs + QCA953X_PLL_CPU_CONFIG_REG);
  42
  43        /* VCOOUT = XTAL * DIV_INT */
  44        div = (val >> QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT)
  45                        & QCA953X_PLL_CPU_CONFIG_REFDIV_MASK;
  46        pll = xtal / div;
  47
  48        /* PLLOUT = VCOOUT * (1/2^OUTDIV) */
  49        div = (val >> QCA953X_PLL_CPU_CONFIG_NINT_SHIFT)
  50                        & QCA953X_PLL_CPU_CONFIG_NINT_MASK;
  51        pll *= div;
  52        div = (val >> QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT)
  53                        & QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK;
  54        if (!div)
  55                div = 1;
  56        pll >>= div;
  57
  58        /* CPU_CLK = PLLOUT / CPU_POST_DIV */
  59        div = ((ctrl >> QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT)
  60                        & QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK) + 1;
  61        gd->cpu_clk = pll / div;
  62
  63
  64        val = readl(regs + QCA953X_PLL_DDR_CONFIG_REG);
  65        /* VCOOUT = XTAL * DIV_INT */
  66        div = (val >> QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT)
  67                        & QCA953X_PLL_DDR_CONFIG_REFDIV_MASK;
  68        pll = xtal / div;
  69
  70        /* PLLOUT = VCOOUT * (1/2^OUTDIV) */
  71        div = (val >> QCA953X_PLL_DDR_CONFIG_NINT_SHIFT)
  72                        & QCA953X_PLL_DDR_CONFIG_NINT_MASK;
  73        pll *= div;
  74        div = (val >> QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT)
  75                        & QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK;
  76        if (!div)
  77                div = 1;
  78        pll >>= div;
  79
  80        /* DDR_CLK = PLLOUT / DDR_POST_DIV */
  81        div = ((ctrl >> QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT)
  82                        & QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK) + 1;
  83        gd->mem_clk = pll / div;
  84
  85        div = ((ctrl >> QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT)
  86                        & QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK) + 1;
  87        if (ctrl & QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL) {
  88                /* AHB_CLK = DDR_CLK / AHB_POST_DIV */
  89                gd->bus_clk = gd->mem_clk / (div + 1);
  90        } else {
  91                /* AHB_CLK = CPU_CLK / AHB_POST_DIV */
  92                gd->bus_clk = gd->cpu_clk / (div + 1);
  93        }
  94
  95        return 0;
  96}
  97
  98ulong get_bus_freq(ulong dummy)
  99{
 100        if (!gd->bus_clk)
 101                get_clocks();
 102        return gd->bus_clk;
 103}
 104
 105ulong get_ddr_freq(ulong dummy)
 106{
 107        if (!gd->mem_clk)
 108                get_clocks();
 109        return gd->mem_clk;
 110}
 111