1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright 2011-2012 Calxeda, Inc.
4 * Copyright (C) 2012-2013 Altera Corporation <www.altera.com>
6 * Based from clk-highbank.c
8 #include <linux/slab.h>
9 #include <linux/clk-provider.h>
12 #include <linux/of_address.h>
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)
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
31 #define CLK_MGR_PLL_CLK_SRC_SHIFT 22
32 #define CLK_MGR_PLL_CLK_SRC_MASK 0x3
34 #define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
36 void __iomem
*clk_mgr_base_addr
;
38 static unsigned long clk_pll_recalc_rate(struct clk_hw
*hwclk
,
39 unsigned long parent_rate
)
41 struct socfpga_pll
*socfpgaclk
= to_socfpga_clk(hwclk
);
42 unsigned long divf
, divq
, reg
;
43 unsigned long long vco_freq
;
46 reg
= readl(socfpgaclk
->hw
.reg
);
47 bypass
= readl(clk_mgr_base_addr
+ CLKMGR_BYPASS
);
48 if (bypass
& MAINPLL_BYPASS
)
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
;
58 static u8
clk_pll_get_parent(struct clk_hw
*hwclk
)
61 struct socfpga_pll
*socfpgaclk
= to_socfpga_clk(hwclk
);
63 pll_src
= readl(socfpgaclk
->hw
.reg
);
64 return (pll_src
>> CLK_MGR_PLL_CLK_SRC_SHIFT
) &
65 CLK_MGR_PLL_CLK_SRC_MASK
;
68 static const struct clk_ops clk_pll_ops
= {
69 .recalc_rate
= clk_pll_recalc_rate
,
70 .get_parent
= clk_pll_get_parent
,
73 static __init
struct clk
*__socfpga_pll_init(struct device_node
*node
,
74 const struct clk_ops
*ops
)
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
;
85 of_property_read_u32(node
, "reg", ®
);
87 pll_clk
= kzalloc(sizeof(*pll_clk
), GFP_KERNEL
);
88 if (WARN_ON(!pll_clk
))
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
;
97 of_property_read_string(node
, "clock-output-names", &clk_name
);
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
;
107 pll_clk
->hw
.bit_idx
= SOCFPGA_PLL_EXT_ENA
;
109 clk
= clk_register(NULL
, &pll_clk
->hw
.hw
);
110 if (WARN_ON(IS_ERR(clk
))) {
114 rc
= of_clk_add_provider(node
, of_clk_src_simple_get
, clk
);
118 void __init
socfpga_pll_init(struct device_node
*node
)
120 __socfpga_pll_init(node
, &clk_pll_ops
);