18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright 2011-2012 Calxeda, Inc.
48c2ecf20Sopenharmony_ci *  Copyright (C) 2012-2013 Altera Corporation <www.altera.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Based from clk-highbank.c
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/of.h>
128c2ecf20Sopenharmony_ci#include <linux/of_address.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "clk.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* Clock bypass bits */
178c2ecf20Sopenharmony_ci#define MAINPLL_BYPASS		(1<<0)
188c2ecf20Sopenharmony_ci#define SDRAMPLL_BYPASS		(1<<1)
198c2ecf20Sopenharmony_ci#define SDRAMPLL_SRC_BYPASS	(1<<2)
208c2ecf20Sopenharmony_ci#define PERPLL_BYPASS		(1<<3)
218c2ecf20Sopenharmony_ci#define PERPLL_SRC_BYPASS	(1<<4)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define SOCFPGA_PLL_BG_PWRDWN		0
248c2ecf20Sopenharmony_ci#define SOCFPGA_PLL_EXT_ENA		1
258c2ecf20Sopenharmony_ci#define SOCFPGA_PLL_PWR_DOWN		2
268c2ecf20Sopenharmony_ci#define SOCFPGA_PLL_DIVF_MASK		0x0000FFF8
278c2ecf20Sopenharmony_ci#define SOCFPGA_PLL_DIVF_SHIFT		3
288c2ecf20Sopenharmony_ci#define SOCFPGA_PLL_DIVQ_MASK		0x003F0000
298c2ecf20Sopenharmony_ci#define SOCFPGA_PLL_DIVQ_SHIFT		16
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define CLK_MGR_PLL_CLK_SRC_SHIFT	22
328c2ecf20Sopenharmony_ci#define CLK_MGR_PLL_CLK_SRC_MASK	0x3
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_civoid __iomem *clk_mgr_base_addr;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
398c2ecf20Sopenharmony_ci					 unsigned long parent_rate)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
428c2ecf20Sopenharmony_ci	unsigned long divf, divq, reg;
438c2ecf20Sopenharmony_ci	unsigned long long vco_freq;
448c2ecf20Sopenharmony_ci	unsigned long bypass;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	reg = readl(socfpgaclk->hw.reg);
478c2ecf20Sopenharmony_ci	bypass = readl(clk_mgr_base_addr + CLKMGR_BYPASS);
488c2ecf20Sopenharmony_ci	if (bypass & MAINPLL_BYPASS)
498c2ecf20Sopenharmony_ci		return parent_rate;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	divf = (reg & SOCFPGA_PLL_DIVF_MASK) >> SOCFPGA_PLL_DIVF_SHIFT;
528c2ecf20Sopenharmony_ci	divq = (reg & SOCFPGA_PLL_DIVQ_MASK) >> SOCFPGA_PLL_DIVQ_SHIFT;
538c2ecf20Sopenharmony_ci	vco_freq = (unsigned long long)parent_rate * (divf + 1);
548c2ecf20Sopenharmony_ci	do_div(vco_freq, (1 + divq));
558c2ecf20Sopenharmony_ci	return (unsigned long)vco_freq;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic u8 clk_pll_get_parent(struct clk_hw *hwclk)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	u32 pll_src;
618c2ecf20Sopenharmony_ci	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	pll_src = readl(socfpgaclk->hw.reg);
648c2ecf20Sopenharmony_ci	return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
658c2ecf20Sopenharmony_ci			CLK_MGR_PLL_CLK_SRC_MASK;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic const struct clk_ops clk_pll_ops = {
698c2ecf20Sopenharmony_ci	.recalc_rate = clk_pll_recalc_rate,
708c2ecf20Sopenharmony_ci	.get_parent = clk_pll_get_parent,
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic __init struct clk_hw *__socfpga_pll_init(struct device_node *node,
748c2ecf20Sopenharmony_ci	const struct clk_ops *ops)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	u32 reg;
778c2ecf20Sopenharmony_ci	struct clk_hw *hw_clk;
788c2ecf20Sopenharmony_ci	struct socfpga_pll *pll_clk;
798c2ecf20Sopenharmony_ci	const char *clk_name = node->name;
808c2ecf20Sopenharmony_ci	const char *parent_name[SOCFPGA_MAX_PARENTS];
818c2ecf20Sopenharmony_ci	struct clk_init_data init;
828c2ecf20Sopenharmony_ci	struct device_node *clkmgr_np;
838c2ecf20Sopenharmony_ci	int rc;
848c2ecf20Sopenharmony_ci	int err;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	of_property_read_u32(node, "reg", &reg);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
898c2ecf20Sopenharmony_ci	if (WARN_ON(!pll_clk))
908c2ecf20Sopenharmony_ci		return NULL;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr");
938c2ecf20Sopenharmony_ci	clk_mgr_base_addr = of_iomap(clkmgr_np, 0);
948c2ecf20Sopenharmony_ci	of_node_put(clkmgr_np);
958c2ecf20Sopenharmony_ci	BUG_ON(!clk_mgr_base_addr);
968c2ecf20Sopenharmony_ci	pll_clk->hw.reg = clk_mgr_base_addr + reg;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	of_property_read_string(node, "clock-output-names", &clk_name);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	init.name = clk_name;
1018c2ecf20Sopenharmony_ci	init.ops = ops;
1028c2ecf20Sopenharmony_ci	init.flags = 0;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	init.num_parents = of_clk_parent_fill(node, parent_name, SOCFPGA_MAX_PARENTS);
1058c2ecf20Sopenharmony_ci	init.parent_names = parent_name;
1068c2ecf20Sopenharmony_ci	pll_clk->hw.hw.init = &init;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	hw_clk = &pll_clk->hw.hw;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	err = clk_hw_register(NULL, hw_clk);
1138c2ecf20Sopenharmony_ci	if (err) {
1148c2ecf20Sopenharmony_ci		kfree(pll_clk);
1158c2ecf20Sopenharmony_ci		return ERR_PTR(err);
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci	rc = of_clk_add_provider(node, of_clk_src_simple_get, hw_clk);
1188c2ecf20Sopenharmony_ci	return hw_clk;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_civoid __init socfpga_pll_init(struct device_node *node)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	__socfpga_pll_init(node, &clk_pll_ops);
1248c2ecf20Sopenharmony_ci}
125