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_MDIV_MASK 0xFF000000 22 #define SOCFPGA_PLL_MDIV_SHIFT 24 23 #define SWCTRLBTCLKSEL_MASK 0x200 24 #define SWCTRLBTCLKSEL_SHIFT 9 25 26 #define SOCFPGA_BOOT_CLK "boot_clk" 27 28 #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw) 29 30 static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, 31 unsigned long parent_rate) 32 { 33 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 34 unsigned long mdiv; 35 unsigned long refdiv; 36 unsigned long reg; 37 unsigned long long vco_freq; 38 39 /* read VCO1 reg for numerator and denominator */ 40 reg = readl(socfpgaclk->hw.reg); 41 refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT; 42 vco_freq = (unsigned long long)parent_rate / refdiv; 43 44 /* Read mdiv and fdiv from the fdbck register */ 45 reg = readl(socfpgaclk->hw.reg + 0x4); 46 mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT; 47 vco_freq = (unsigned long long)vco_freq * (mdiv + 6); 48 49 return (unsigned long)vco_freq; 50 } 51 52 static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk, 53 unsigned long parent_rate) 54 { 55 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 56 u32 div = 1; 57 58 div = ((readl(socfpgaclk->hw.reg) & 59 SWCTRLBTCLKSEL_MASK) >> 60 SWCTRLBTCLKSEL_SHIFT); 61 div += 1; 62 return parent_rate /= div; 63 } 64 65 66 static u8 clk_pll_get_parent(struct clk_hw *hwclk) 67 { 68 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 69 u32 pll_src; 70 71 pll_src = readl(socfpgaclk->hw.reg); 72 return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) & 73 CLK_MGR_PLL_CLK_SRC_MASK; 74 } 75 76 static u8 clk_boot_get_parent(struct clk_hw *hwclk) 77 { 78 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 79 u32 pll_src; 80 81 pll_src = readl(socfpgaclk->hw.reg); 82 return (pll_src >> SWCTRLBTCLKSEL_SHIFT) & 83 SWCTRLBTCLKSEL_MASK; 84 } 85 86 static int clk_pll_prepare(struct clk_hw *hwclk) 87 { 88 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 89 u32 reg; 90 91 /* Bring PLL out of reset */ 92 reg = readl(socfpgaclk->hw.reg); 93 reg |= SOCFPGA_PLL_RESET_MASK; 94 writel(reg, socfpgaclk->hw.reg); 95 96 return 0; 97 } 98 99 static struct clk_ops clk_pll_ops = { 100 .recalc_rate = clk_pll_recalc_rate, 101 .get_parent = clk_pll_get_parent, 102 .prepare = clk_pll_prepare, 103 }; 104 105 static struct clk_ops clk_boot_ops = { 106 .recalc_rate = clk_boot_clk_recalc_rate, 107 .get_parent = clk_boot_get_parent, 108 .prepare = clk_pll_prepare, 109 }; 110 111 struct clk *s10_register_pll(const char *name, const char * const *parent_names, 112 u8 num_parents, unsigned long flags, 113 void __iomem *reg, unsigned long offset) 114 { 115 struct clk *clk; 116 struct socfpga_pll *pll_clk; 117 struct clk_init_data init; 118 119 pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); 120 if (WARN_ON(!pll_clk)) 121 return NULL; 122 123 pll_clk->hw.reg = reg + offset; 124 125 if (streq(name, SOCFPGA_BOOT_CLK)) 126 init.ops = &clk_boot_ops; 127 else 128 init.ops = &clk_pll_ops; 129 130 init.name = name; 131 init.flags = flags; 132 133 init.num_parents = num_parents; 134 init.parent_names = parent_names; 135 pll_clk->hw.hw.init = &init; 136 137 pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER; 138 clk_pll_ops.enable = clk_gate_ops.enable; 139 clk_pll_ops.disable = clk_gate_ops.disable; 140 141 clk = clk_register(NULL, &pll_clk->hw.hw); 142 if (WARN_ON(IS_ERR(clk))) { 143 kfree(pll_clk); 144 return NULL; 145 } 146 return clk; 147 } 148