1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2015 Altera Corporation. All rights reserved |
4 | */ |
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 8 |
15 | #define CLK_MGR_PLL_CLK_SRC_MASK 0x3 |
16 | |
17 | /* Clock bypass bits */ |
18 | #define SOCFPGA_PLL_BG_PWRDWN 0 |
19 | #define SOCFPGA_PLL_PWR_DOWN 1 |
20 | #define SOCFPGA_PLL_EXT_ENA 2 |
21 | #define SOCFPGA_PLL_DIVF_MASK 0x00001FFF |
22 | #define SOCFPGA_PLL_DIVF_SHIFT 0 |
23 | #define SOCFPGA_PLL_DIVQ_MASK 0x003F0000 |
24 | #define SOCFPGA_PLL_DIVQ_SHIFT 16 |
25 | #define SOCFGPA_MAX_PARENTS 5 |
26 | |
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 | |
32 | void __iomem *clk_mgr_a10_base_addr; |
33 | |
34 | static 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(addr: 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 | |
50 | static 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(addr: socfpgaclk->hw.reg); |
56 | |
57 | return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) & |
58 | CLK_MGR_PLL_CLK_SRC_MASK; |
59 | } |
60 | |
61 | static const struct clk_ops clk_pll_ops = { |
62 | .recalc_rate = clk_pll_recalc_rate, |
63 | .get_parent = clk_pll_get_parent, |
64 | }; |
65 | |
66 | static 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(np: node, propname: "reg" , out_value: ®); |
80 | |
81 | pll_clk = kzalloc(size: sizeof(*pll_clk), GFP_KERNEL); |
82 | if (WARN_ON(!pll_clk)) |
83 | return; |
84 | |
85 | clkmgr_np = of_find_compatible_node(NULL, NULL, compat: "altr,clk-mgr" ); |
86 | clk_mgr_a10_base_addr = of_iomap(node: clkmgr_np, index: 0); |
87 | of_node_put(node: 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(np: node, propname: "clock-output-names" , out_string: &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(np: node, index: 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: 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(np: node, get: of_clk_hw_simple_get, data: 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 | |
122 | err_of_clk_add_hw_provider: |
123 | clk_hw_unregister(hw: hw_clk); |
124 | err_clk_hw_register: |
125 | kfree(objp: pll_clk); |
126 | } |
127 | |
128 | void __init socfpga_a10_pll_init(struct device_node *node) |
129 | { |
130 | __socfpga_pll_init(node, ops: &clk_pll_ops); |
131 | } |
132 | |