Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.4-rc2 147 lines 3.7 kB view raw
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 30static 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 52static 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 66static 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 76static 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 86static 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 99static 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 105static 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 111struct 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}