linux/drivers/clk/socfpga/clk-pll-s10.c
<<
>>
Prefs
   1// SPDX-License-Identifier:     GPL-2.0
   2/*
   3 * Copyright (C) 2017, Intel Corporation
   4 */
   5#include <linux/slab.h>
   6#include <linux/clk-provider.h>
   7#include <linux/io.h>
   8
   9#include "stratix10-clk.h"
  10#include "clk.h"
  11
  12/* Clock Manager offsets */
  13#define CLK_MGR_PLL_CLK_SRC_SHIFT       16
  14#define CLK_MGR_PLL_CLK_SRC_MASK        0x3
  15
  16/* PLL Clock enable bits */
  17#define SOCFPGA_PLL_POWER               0
  18#define SOCFPGA_PLL_RESET_MASK          0x2
  19#define SOCFPGA_PLL_REFDIV_MASK         0x00003F00
  20#define SOCFPGA_PLL_REFDIV_SHIFT        8
  21#define SOCFPGA_PLL_AREFDIV_MASK        0x00000F00
  22#define SOCFPGA_PLL_DREFDIV_MASK        0x00003000
  23#define SOCFPGA_PLL_DREFDIV_SHIFT       12
  24#define SOCFPGA_PLL_MDIV_MASK           0xFF000000
  25#define SOCFPGA_PLL_MDIV_SHIFT          24
  26#define SOCFPGA_AGILEX_PLL_MDIV_MASK    0x000003FF
  27#define SWCTRLBTCLKSEL_MASK             0x200
  28#define SWCTRLBTCLKSEL_SHIFT            9
  29
  30#define SOCFPGA_BOOT_CLK                "boot_clk"
  31
  32#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
  33
  34static unsigned long agilex_clk_pll_recalc_rate(struct clk_hw *hwclk,
  35                                                unsigned long parent_rate)
  36{
  37        struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
  38        unsigned long arefdiv, reg, mdiv;
  39        unsigned long long vco_freq;
  40
  41        /* read VCO1 reg for numerator and denominator */
  42        reg = readl(socfpgaclk->hw.reg);
  43        arefdiv = (reg & SOCFPGA_PLL_AREFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
  44
  45        vco_freq = (unsigned long long)parent_rate / arefdiv;
  46
  47        /* Read mdiv and fdiv from the fdbck register */
  48        reg = readl(socfpgaclk->hw.reg + 0x24);
  49        mdiv = reg & SOCFPGA_AGILEX_PLL_MDIV_MASK;
  50
  51        vco_freq = (unsigned long long)vco_freq * mdiv;
  52        return (unsigned long)vco_freq;
  53}
  54
  55static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
  56                                         unsigned long parent_rate)
  57{
  58        struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
  59        unsigned long mdiv;
  60        unsigned long refdiv;
  61        unsigned long reg;
  62        unsigned long long vco_freq;
  63
  64        /* read VCO1 reg for numerator and denominator */
  65        reg = readl(socfpgaclk->hw.reg);
  66        refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
  67
  68        vco_freq = parent_rate;
  69        do_div(vco_freq, refdiv);
  70
  71        /* Read mdiv and fdiv from the fdbck register */
  72        reg = readl(socfpgaclk->hw.reg + 0x4);
  73        mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT;
  74        vco_freq = (unsigned long long)vco_freq * (mdiv + 6);
  75
  76        return (unsigned long)vco_freq;
  77}
  78
  79static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk,
  80                                         unsigned long parent_rate)
  81{
  82        struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
  83        u32 div = 1;
  84
  85        div = ((readl(socfpgaclk->hw.reg) &
  86                SWCTRLBTCLKSEL_MASK) >>
  87                SWCTRLBTCLKSEL_SHIFT);
  88        div += 1;
  89        return parent_rate /= div;
  90}
  91
  92
  93static u8 clk_pll_get_parent(struct clk_hw *hwclk)
  94{
  95        struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
  96        u32 pll_src;
  97
  98        pll_src = readl(socfpgaclk->hw.reg);
  99        return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
 100                CLK_MGR_PLL_CLK_SRC_MASK;
 101}
 102
 103static u8 clk_boot_get_parent(struct clk_hw *hwclk)
 104{
 105        struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
 106        u32 pll_src;
 107
 108        pll_src = readl(socfpgaclk->hw.reg);
 109        return (pll_src >> SWCTRLBTCLKSEL_SHIFT) &
 110                SWCTRLBTCLKSEL_MASK;
 111}
 112
 113static int clk_pll_prepare(struct clk_hw *hwclk)
 114{
 115        struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
 116        u32 reg;
 117
 118        /* Bring PLL out of reset */
 119        reg = readl(socfpgaclk->hw.reg);
 120        reg |= SOCFPGA_PLL_RESET_MASK;
 121        writel(reg, socfpgaclk->hw.reg);
 122
 123        return 0;
 124}
 125
 126static const struct clk_ops agilex_clk_pll_ops = {
 127        .recalc_rate = agilex_clk_pll_recalc_rate,
 128        .get_parent = clk_pll_get_parent,
 129        .prepare = clk_pll_prepare,
 130};
 131
 132static const struct clk_ops clk_pll_ops = {
 133        .recalc_rate = clk_pll_recalc_rate,
 134        .get_parent = clk_pll_get_parent,
 135        .prepare = clk_pll_prepare,
 136};
 137
 138static const struct clk_ops clk_boot_ops = {
 139        .recalc_rate = clk_boot_clk_recalc_rate,
 140        .get_parent = clk_boot_get_parent,
 141        .prepare = clk_pll_prepare,
 142};
 143
 144struct clk *s10_register_pll(const struct stratix10_pll_clock *clks,
 145                             void __iomem *reg)
 146{
 147        struct clk *clk;
 148        struct socfpga_pll *pll_clk;
 149        struct clk_init_data init;
 150        const char *name = clks->name;
 151
 152        pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
 153        if (WARN_ON(!pll_clk))
 154                return NULL;
 155
 156        pll_clk->hw.reg = reg + clks->offset;
 157
 158        if (streq(name, SOCFPGA_BOOT_CLK))
 159                init.ops = &clk_boot_ops;
 160        else
 161                init.ops = &clk_pll_ops;
 162
 163        init.name = name;
 164        init.flags = clks->flags;
 165
 166        init.num_parents = clks->num_parents;
 167        init.parent_names = NULL;
 168        init.parent_data = clks->parent_data;
 169        pll_clk->hw.hw.init = &init;
 170
 171        pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
 172
 173        clk = clk_register(NULL, &pll_clk->hw.hw);
 174        if (WARN_ON(IS_ERR(clk))) {
 175                kfree(pll_clk);
 176                return NULL;
 177        }
 178        return clk;
 179}
 180
 181struct clk *agilex_register_pll(const struct stratix10_pll_clock *clks,
 182                                void __iomem *reg)
 183{
 184        struct clk *clk;
 185        struct socfpga_pll *pll_clk;
 186        struct clk_init_data init;
 187        const char *name = clks->name;
 188
 189        pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
 190        if (WARN_ON(!pll_clk))
 191                return NULL;
 192
 193        pll_clk->hw.reg = reg + clks->offset;
 194
 195        if (streq(name, SOCFPGA_BOOT_CLK))
 196                init.ops = &clk_boot_ops;
 197        else
 198                init.ops = &agilex_clk_pll_ops;
 199
 200        init.name = name;
 201        init.flags = clks->flags;
 202
 203        init.num_parents = clks->num_parents;
 204        init.parent_names = NULL;
 205        init.parent_data = clks->parent_data;
 206        pll_clk->hw.hw.init = &init;
 207
 208        pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;
 209
 210        clk = clk_register(NULL, &pll_clk->hw.hw);
 211        if (WARN_ON(IS_ERR(clk))) {
 212                kfree(pll_clk);
 213                return NULL;
 214        }
 215        return clk;
 216}
 217