clk-pll.c (3228B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright 2011-2012 Calxeda, Inc. 4 * Copyright (C) 2012-2013 Altera Corporation <www.altera.com> 5 * 6 * Based from clk-highbank.c 7 */ 8#include <linux/slab.h> 9#include <linux/clk-provider.h> 10#include <linux/io.h> 11#include <linux/of.h> 12#include <linux/of_address.h> 13 14#include "clk.h" 15 16/* Clock bypass bits */ 17#define MAINPLL_BYPASS (1<<0) 18#define SDRAMPLL_BYPASS (1<<1) 19#define SDRAMPLL_SRC_BYPASS (1<<2) 20#define PERPLL_BYPASS (1<<3) 21#define PERPLL_SRC_BYPASS (1<<4) 22 23#define SOCFPGA_PLL_BG_PWRDWN 0 24#define SOCFPGA_PLL_EXT_ENA 1 25#define SOCFPGA_PLL_PWR_DOWN 2 26#define SOCFPGA_PLL_DIVF_MASK 0x0000FFF8 27#define SOCFPGA_PLL_DIVF_SHIFT 3 28#define SOCFPGA_PLL_DIVQ_MASK 0x003F0000 29#define SOCFPGA_PLL_DIVQ_SHIFT 16 30 31#define CLK_MGR_PLL_CLK_SRC_SHIFT 22 32#define CLK_MGR_PLL_CLK_SRC_MASK 0x3 33 34#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw) 35 36void __iomem *clk_mgr_base_addr; 37 38static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, 39 unsigned long parent_rate) 40{ 41 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 42 unsigned long divf, divq, reg; 43 unsigned long long vco_freq; 44 unsigned long bypass; 45 46 reg = readl(socfpgaclk->hw.reg); 47 bypass = readl(clk_mgr_base_addr + CLKMGR_BYPASS); 48 if (bypass & MAINPLL_BYPASS) 49 return parent_rate; 50 51 divf = (reg & SOCFPGA_PLL_DIVF_MASK) >> SOCFPGA_PLL_DIVF_SHIFT; 52 divq = (reg & SOCFPGA_PLL_DIVQ_MASK) >> SOCFPGA_PLL_DIVQ_SHIFT; 53 vco_freq = (unsigned long long)parent_rate * (divf + 1); 54 do_div(vco_freq, (1 + divq)); 55 return (unsigned long)vco_freq; 56} 57 58static u8 clk_pll_get_parent(struct clk_hw *hwclk) 59{ 60 u32 pll_src; 61 struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk); 62 63 pll_src = readl(socfpgaclk->hw.reg); 64 return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) & 65 CLK_MGR_PLL_CLK_SRC_MASK; 66} 67 68static const struct clk_ops clk_pll_ops = { 69 .recalc_rate = clk_pll_recalc_rate, 70 .get_parent = clk_pll_get_parent, 71}; 72 73static __init struct clk_hw *__socfpga_pll_init(struct device_node *node, 74 const struct clk_ops *ops) 75{ 76 u32 reg; 77 struct clk_hw *hw_clk; 78 struct socfpga_pll *pll_clk; 79 const char *clk_name = node->name; 80 const char *parent_name[SOCFPGA_MAX_PARENTS]; 81 struct clk_init_data init; 82 struct device_node *clkmgr_np; 83 int err; 84 85 of_property_read_u32(node, "reg", ®); 86 87 pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); 88 if (WARN_ON(!pll_clk)) 89 return NULL; 90 91 clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); 92 clk_mgr_base_addr = of_iomap(clkmgr_np, 0); 93 of_node_put(clkmgr_np); 94 BUG_ON(!clk_mgr_base_addr); 95 pll_clk->hw.reg = clk_mgr_base_addr + reg; 96 97 of_property_read_string(node, "clock-output-names", &clk_name); 98 99 init.name = clk_name; 100 init.ops = ops; 101 init.flags = 0; 102 103 init.num_parents = of_clk_parent_fill(node, parent_name, SOCFPGA_MAX_PARENTS); 104 init.parent_names = parent_name; 105 pll_clk->hw.hw.init = &init; 106 107 pll_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA; 108 109 hw_clk = &pll_clk->hw.hw; 110 111 err = clk_hw_register(NULL, hw_clk); 112 if (err) { 113 kfree(pll_clk); 114 return ERR_PTR(err); 115 } 116 of_clk_add_provider(node, of_clk_src_simple_get, hw_clk); 117 return hw_clk; 118} 119 120void __init socfpga_pll_init(struct device_node *node) 121{ 122 __socfpga_pll_init(node, &clk_pll_ops); 123}