brintos

brintos / linux-shallow public Read only

0
0
Text · 7.4 KiB · 1d82737 Raw
307 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2017, Intel Corporation4 */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	1614#define CLK_MGR_PLL_CLK_SRC_MASK	0x315 16/* PLL Clock enable bits */17#define SOCFPGA_PLL_POWER		018#define SOCFPGA_PLL_RESET_MASK		0x219#define SOCFPGA_PLL_REFDIV_MASK		0x00003F0020#define SOCFPGA_PLL_REFDIV_SHIFT	821#define SOCFPGA_PLL_AREFDIV_MASK	0x00000F0022#define SOCFPGA_PLL_DREFDIV_MASK	0x0000300023#define SOCFPGA_PLL_DREFDIV_SHIFT	1224#define SOCFPGA_PLL_MDIV_MASK		0xFF00000025#define SOCFPGA_PLL_MDIV_SHIFT		2426#define SOCFPGA_AGILEX_PLL_MDIV_MASK	0x000003FF27#define SWCTRLBTCLKSEL_MASK		0x20028#define SWCTRLBTCLKSEL_SHIFT		929 30#define SOCFPGA_N5X_PLLDIV_FDIV_MASK	GENMASK(16, 8)31#define SOCFPGA_N5X_PLLDIV_FDIV_SHIFT	832#define SOCFPGA_N5X_PLLDIV_RDIV_MASK	GENMASK(5, 0)33#define SOCFPGA_N5X_PLLDIV_QDIV_MASK	GENMASK(26, 24)34#define SOCFPGA_N5X_PLLDIV_QDIV_SHIFT	2435 36#define SOCFPGA_BOOT_CLK		"boot_clk"37 38#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)39 40static unsigned long n5x_clk_pll_recalc_rate(struct clk_hw *hwclk,41						unsigned long parent_rate)42{43	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);44	unsigned long fdiv, reg, rdiv, qdiv;45	u32 power = 1;46 47	/* read VCO1 reg for numerator and denominator */48	reg = readl(socfpgaclk->hw.reg + 0x8);49	fdiv = (reg & SOCFPGA_N5X_PLLDIV_FDIV_MASK) >> SOCFPGA_N5X_PLLDIV_FDIV_SHIFT;50	rdiv = (reg & SOCFPGA_N5X_PLLDIV_RDIV_MASK);51	qdiv = (reg & SOCFPGA_N5X_PLLDIV_QDIV_MASK) >> SOCFPGA_N5X_PLLDIV_QDIV_SHIFT;52 53	while (qdiv) {54		power *= 2;55		qdiv--;56	}57 58	return ((parent_rate * 2 * (fdiv + 1)) / ((rdiv + 1) * power));59}60 61static unsigned long agilex_clk_pll_recalc_rate(struct clk_hw *hwclk,62						unsigned long parent_rate)63{64	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);65	unsigned long arefdiv, reg, mdiv;66	unsigned long long vco_freq;67 68	/* read VCO1 reg for numerator and denominator */69	reg = readl(socfpgaclk->hw.reg);70	arefdiv = (reg & SOCFPGA_PLL_AREFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;71 72	vco_freq = (unsigned long long)parent_rate / arefdiv;73 74	/* Read mdiv and fdiv from the fdbck register */75	reg = readl(socfpgaclk->hw.reg + 0x24);76	mdiv = reg & SOCFPGA_AGILEX_PLL_MDIV_MASK;77 78	vco_freq = (unsigned long long)vco_freq * mdiv;79	return (unsigned long)vco_freq;80}81 82static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,83					 unsigned long parent_rate)84{85	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);86	unsigned long mdiv;87	unsigned long refdiv;88	unsigned long reg;89	unsigned long long vco_freq;90 91	/* read VCO1 reg for numerator and denominator */92	reg = readl(socfpgaclk->hw.reg);93	refdiv = (reg & SOCFPGA_PLL_REFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;94 95	vco_freq = parent_rate;96	do_div(vco_freq, refdiv);97 98	/* Read mdiv and fdiv from the fdbck register */99	reg = readl(socfpgaclk->hw.reg + 0x4);100	mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT;101	vco_freq = (unsigned long long)vco_freq * (mdiv + 6);102 103	return (unsigned long)vco_freq;104}105 106static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk,107					 unsigned long parent_rate)108{109	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);110	u32 div;111 112	div = ((readl(socfpgaclk->hw.reg) &113		SWCTRLBTCLKSEL_MASK) >>114		SWCTRLBTCLKSEL_SHIFT);115	div += 1;116	return parent_rate / div;117}118 119 120static u8 clk_pll_get_parent(struct clk_hw *hwclk)121{122	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);123	u32 pll_src;124 125	pll_src = readl(socfpgaclk->hw.reg);126	return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &127		CLK_MGR_PLL_CLK_SRC_MASK;128}129 130static u8 clk_boot_get_parent(struct clk_hw *hwclk)131{132	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);133	u32 pll_src;134 135	pll_src = readl(socfpgaclk->hw.reg);136	return (pll_src >> SWCTRLBTCLKSEL_SHIFT) &137		SWCTRLBTCLKSEL_MASK;138}139 140static int clk_pll_prepare(struct clk_hw *hwclk)141{142	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);143	u32 reg;144 145	/* Bring PLL out of reset */146	reg = readl(socfpgaclk->hw.reg);147	reg |= SOCFPGA_PLL_RESET_MASK;148	writel(reg, socfpgaclk->hw.reg);149 150	return 0;151}152 153static int n5x_clk_pll_prepare(struct clk_hw *hwclk)154{155	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);156	u32 reg;157 158	/* Bring PLL out of reset */159	reg = readl(socfpgaclk->hw.reg + 0x4);160	reg |= SOCFPGA_PLL_RESET_MASK;161	writel(reg, socfpgaclk->hw.reg + 0x4);162 163	return 0;164}165 166static const struct clk_ops n5x_clk_pll_ops = {167	.recalc_rate = n5x_clk_pll_recalc_rate,168	.get_parent = clk_pll_get_parent,169	.prepare = n5x_clk_pll_prepare,170};171 172static const struct clk_ops agilex_clk_pll_ops = {173	.recalc_rate = agilex_clk_pll_recalc_rate,174	.get_parent = clk_pll_get_parent,175	.prepare = clk_pll_prepare,176};177 178static const struct clk_ops clk_pll_ops = {179	.recalc_rate = clk_pll_recalc_rate,180	.get_parent = clk_pll_get_parent,181	.prepare = clk_pll_prepare,182};183 184static const struct clk_ops clk_boot_ops = {185	.recalc_rate = clk_boot_clk_recalc_rate,186	.get_parent = clk_boot_get_parent,187	.prepare = clk_pll_prepare,188};189 190struct clk_hw *s10_register_pll(const struct stratix10_pll_clock *clks,191			     void __iomem *reg)192{193	struct clk_hw *hw_clk;194	struct socfpga_pll *pll_clk;195	struct clk_init_data init;196	const char *name = clks->name;197	int ret;198 199	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);200	if (WARN_ON(!pll_clk))201		return NULL;202 203	pll_clk->hw.reg = reg + clks->offset;204 205	if (streq(name, SOCFPGA_BOOT_CLK))206		init.ops = &clk_boot_ops;207	else208		init.ops = &clk_pll_ops;209 210	init.name = name;211	init.flags = clks->flags;212 213	init.num_parents = clks->num_parents;214	init.parent_names = NULL;215	init.parent_data = clks->parent_data;216	pll_clk->hw.hw.init = &init;217 218	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;219 220	hw_clk = &pll_clk->hw.hw;221 222	ret = clk_hw_register(NULL, hw_clk);223	if (ret) {224		kfree(pll_clk);225		return ERR_PTR(ret);226	}227	return hw_clk;228}229 230struct clk_hw *agilex_register_pll(const struct stratix10_pll_clock *clks,231				void __iomem *reg)232{233	struct clk_hw *hw_clk;234	struct socfpga_pll *pll_clk;235	struct clk_init_data init;236	const char *name = clks->name;237	int ret;238 239	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);240	if (WARN_ON(!pll_clk))241		return NULL;242 243	pll_clk->hw.reg = reg + clks->offset;244 245	if (streq(name, SOCFPGA_BOOT_CLK))246		init.ops = &clk_boot_ops;247	else248		init.ops = &agilex_clk_pll_ops;249 250	init.name = name;251	init.flags = clks->flags;252 253	init.num_parents = clks->num_parents;254	init.parent_names = NULL;255	init.parent_data = clks->parent_data;256	pll_clk->hw.hw.init = &init;257 258	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;259	hw_clk = &pll_clk->hw.hw;260 261	ret = clk_hw_register(NULL, hw_clk);262	if (ret) {263		kfree(pll_clk);264		return ERR_PTR(ret);265	}266	return hw_clk;267}268 269struct clk_hw *n5x_register_pll(const struct stratix10_pll_clock *clks,270			     void __iomem *reg)271{272	struct clk_hw *hw_clk;273	struct socfpga_pll *pll_clk;274	struct clk_init_data init;275	const char *name = clks->name;276	int ret;277 278	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);279	if (WARN_ON(!pll_clk))280		return NULL;281 282	pll_clk->hw.reg = reg + clks->offset;283 284	if (streq(name, SOCFPGA_BOOT_CLK))285		init.ops = &clk_boot_ops;286	else287		init.ops = &n5x_clk_pll_ops;288 289	init.name = name;290	init.flags = clks->flags;291 292	init.num_parents = clks->num_parents;293	init.parent_names = NULL;294	init.parent_data = clks->parent_data;295	pll_clk->hw.hw.init = &init;296 297	pll_clk->hw.bit_idx = SOCFPGA_PLL_POWER;298	hw_clk = &pll_clk->hw.hw;299 300	ret = clk_hw_register(NULL, hw_clk);301	if (ret) {302		kfree(pll_clk);303		return ERR_PTR(ret);304	}305	return hw_clk;306}307