| .. | .. |
|---|
| 4 | 4 | */ |
|---|
| 5 | 5 | #include <linux/slab.h> |
|---|
| 6 | 6 | #include <linux/clk-provider.h> |
|---|
| 7 | +#include <linux/io.h> |
|---|
| 7 | 8 | |
|---|
| 8 | 9 | #include "stratix10-clk.h" |
|---|
| 9 | 10 | #include "clk.h" |
|---|
| .. | .. |
|---|
| 17 | 18 | #define SOCFPGA_PLL_RESET_MASK 0x2 |
|---|
| 18 | 19 | #define SOCFPGA_PLL_REFDIV_MASK 0x00003F00 |
|---|
| 19 | 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 |
|---|
| 20 | 24 | #define SOCFPGA_PLL_MDIV_MASK 0xFF000000 |
|---|
| 21 | 25 | #define SOCFPGA_PLL_MDIV_SHIFT 24 |
|---|
| 26 | +#define SOCFPGA_AGILEX_PLL_MDIV_MASK 0x000003FF |
|---|
| 22 | 27 | #define SWCTRLBTCLKSEL_MASK 0x200 |
|---|
| 23 | 28 | #define SWCTRLBTCLKSEL_SHIFT 9 |
|---|
| 24 | 29 | |
|---|
| 25 | 30 | #define SOCFPGA_BOOT_CLK "boot_clk" |
|---|
| 26 | 31 | |
|---|
| 27 | 32 | #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw) |
|---|
| 33 | + |
|---|
| 34 | +static 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 | +} |
|---|
| 28 | 54 | |
|---|
| 29 | 55 | static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, |
|---|
| 30 | 56 | unsigned long parent_rate) |
|---|
| .. | .. |
|---|
| 97 | 123 | return 0; |
|---|
| 98 | 124 | } |
|---|
| 99 | 125 | |
|---|
| 100 | | -static struct clk_ops clk_pll_ops = { |
|---|
| 126 | +static 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 | + |
|---|
| 132 | +static const struct clk_ops clk_pll_ops = { |
|---|
| 101 | 133 | .recalc_rate = clk_pll_recalc_rate, |
|---|
| 102 | 134 | .get_parent = clk_pll_get_parent, |
|---|
| 103 | 135 | .prepare = clk_pll_prepare, |
|---|
| 104 | 136 | }; |
|---|
| 105 | 137 | |
|---|
| 106 | | -static struct clk_ops clk_boot_ops = { |
|---|
| 138 | +static const struct clk_ops clk_boot_ops = { |
|---|
| 107 | 139 | .recalc_rate = clk_boot_clk_recalc_rate, |
|---|
| 108 | 140 | .get_parent = clk_boot_get_parent, |
|---|
| 109 | 141 | .prepare = clk_pll_prepare, |
|---|
| 110 | 142 | }; |
|---|
| 111 | 143 | |
|---|
| 112 | | -struct clk *s10_register_pll(const char *name, const char * const *parent_names, |
|---|
| 113 | | - u8 num_parents, unsigned long flags, |
|---|
| 114 | | - void __iomem *reg, unsigned long offset) |
|---|
| 144 | +struct clk *s10_register_pll(const struct stratix10_pll_clock *clks, |
|---|
| 145 | + void __iomem *reg) |
|---|
| 115 | 146 | { |
|---|
| 116 | 147 | struct clk *clk; |
|---|
| 117 | 148 | struct socfpga_pll *pll_clk; |
|---|
| 118 | | - struct clk_init_data init = {}; |
|---|
| 149 | + struct clk_init_data init; |
|---|
| 150 | + const char *name = clks->name; |
|---|
| 119 | 151 | |
|---|
| 120 | 152 | pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); |
|---|
| 121 | 153 | if (WARN_ON(!pll_clk)) |
|---|
| 122 | 154 | return NULL; |
|---|
| 123 | 155 | |
|---|
| 124 | | - pll_clk->hw.reg = reg + offset; |
|---|
| 156 | + pll_clk->hw.reg = reg + clks->offset; |
|---|
| 125 | 157 | |
|---|
| 126 | 158 | if (streq(name, SOCFPGA_BOOT_CLK)) |
|---|
| 127 | 159 | init.ops = &clk_boot_ops; |
|---|
| .. | .. |
|---|
| 129 | 161 | init.ops = &clk_pll_ops; |
|---|
| 130 | 162 | |
|---|
| 131 | 163 | init.name = name; |
|---|
| 132 | | - init.flags = flags; |
|---|
| 164 | + init.flags = clks->flags; |
|---|
| 133 | 165 | |
|---|
| 134 | | - init.num_parents = num_parents; |
|---|
| 135 | | - init.parent_names = parent_names; |
|---|
| 166 | + init.num_parents = clks->num_parents; |
|---|
| 167 | + init.parent_names = NULL; |
|---|
| 168 | + init.parent_data = clks->parent_data; |
|---|
| 136 | 169 | pll_clk->hw.hw.init = &init; |
|---|
| 137 | 170 | |
|---|
| 138 | 171 | pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER; |
|---|
| 139 | | - clk_pll_ops.enable = clk_gate_ops.enable; |
|---|
| 140 | | - clk_pll_ops.disable = clk_gate_ops.disable; |
|---|
| 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 | + |
|---|
| 181 | +struct 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; |
|---|
| 141 | 209 | |
|---|
| 142 | 210 | clk = clk_register(NULL, &pll_clk->hw.hw); |
|---|
| 143 | 211 | if (WARN_ON(IS_ERR(clk))) { |
|---|