132 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2015 Altera Corporation. All rights reserved4 */5#include <linux/slab.h>6#include <linux/clk-provider.h>7#include <linux/io.h>8#include <linux/of.h>9#include <linux/of_address.h>10 11#include "clk.h"12 13/* Clock Manager offsets */14#define CLK_MGR_PLL_CLK_SRC_SHIFT 815#define CLK_MGR_PLL_CLK_SRC_MASK 0x316 17/* Clock bypass bits */18#define SOCFPGA_PLL_BG_PWRDWN 019#define SOCFPGA_PLL_PWR_DOWN 120#define SOCFPGA_PLL_EXT_ENA 221#define SOCFPGA_PLL_DIVF_MASK 0x00001FFF22#define SOCFPGA_PLL_DIVF_SHIFT 023#define SOCFPGA_PLL_DIVQ_MASK 0x003F000024#define SOCFPGA_PLL_DIVQ_SHIFT 1625#define SOCFGPA_MAX_PARENTS 526 27#define SOCFPGA_MAIN_PLL_CLK "main_pll"28#define SOCFPGA_PERIP_PLL_CLK "periph_pll"29 30#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)31 32void __iomem *clk_mgr_a10_base_addr;33 34static unsigned long 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 divf, divq, reg;39 unsigned long long vco_freq;40 41 /* read VCO1 reg for numerator and denominator */42 reg = readl(socfpgaclk->hw.reg + 0x4);43 divf = (reg & SOCFPGA_PLL_DIVF_MASK) >> SOCFPGA_PLL_DIVF_SHIFT;44 divq = (reg & SOCFPGA_PLL_DIVQ_MASK) >> SOCFPGA_PLL_DIVQ_SHIFT;45 vco_freq = (unsigned long long)parent_rate * (divf + 1);46 do_div(vco_freq, (1 + divq));47 return (unsigned long)vco_freq;48}49 50static u8 clk_pll_get_parent(struct clk_hw *hwclk)51{52 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);53 u32 pll_src;54 55 pll_src = readl(socfpgaclk->hw.reg);56 57 return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &58 CLK_MGR_PLL_CLK_SRC_MASK;59}60 61static const struct clk_ops clk_pll_ops = {62 .recalc_rate = clk_pll_recalc_rate,63 .get_parent = clk_pll_get_parent,64};65 66static void __init __socfpga_pll_init(struct device_node *node,67 const struct clk_ops *ops)68{69 u32 reg;70 struct clk_hw *hw_clk;71 struct socfpga_pll *pll_clk;72 const char *clk_name = node->name;73 const char *parent_name[SOCFGPA_MAX_PARENTS];74 struct clk_init_data init;75 struct device_node *clkmgr_np;76 int rc;77 int i = 0;78 79 of_property_read_u32(node, "reg", ®);80 81 pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);82 if (WARN_ON(!pll_clk))83 return;84 85 clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr");86 clk_mgr_a10_base_addr = of_iomap(clkmgr_np, 0);87 of_node_put(clkmgr_np);88 BUG_ON(!clk_mgr_a10_base_addr);89 pll_clk->hw.reg = clk_mgr_a10_base_addr + reg;90 91 of_property_read_string(node, "clock-output-names", &clk_name);92 93 init.name = clk_name;94 init.ops = ops;95 init.flags = 0;96 97 while (i < SOCFGPA_MAX_PARENTS && (parent_name[i] =98 of_clk_get_parent_name(node, i)) != NULL)99 i++;100 init.num_parents = i;101 init.parent_names = parent_name;102 pll_clk->hw.hw.init = &init;103 104 pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;105 hw_clk = &pll_clk->hw.hw;106 107 rc = clk_hw_register(NULL, hw_clk);108 if (rc) {109 pr_err("Could not register clock:%s\n", clk_name);110 goto err_clk_hw_register;111 }112 113 rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw_clk);114 if (rc) {115 pr_err("Could not register clock provider for node:%s\n",116 clk_name);117 goto err_of_clk_add_hw_provider;118 }119 120 return;121 122err_of_clk_add_hw_provider:123 clk_hw_unregister(hw_clk);124err_clk_hw_register:125 kfree(pll_clk);126}127 128void __init socfpga_a10_pll_init(struct device_node *node)129{130 __socfpga_pll_init(node, &clk_pll_ops);131}132